Difference between revisions of "Vertex Transformation"

From OpenGL Wiki
Jump to: navigation, search
m (deprecation.)
(Making correction and adding other examples)
Line 1: Line 1:
 
{{deprecated}}
 
{{deprecated}}
  
This page contains a small example that shows how a vertex is transformed.<br>
+
This page contains a small example that shows how a vertex is transformed.
This page will demonstrate:<br>
+
 
object space ---> world space<br>
+
This page will demonstrate:
world space ---> eye space<br>
+
* object space ---> world space
eye space ---> clip space<br>
+
* world space ---> eye space
clip space ---> normalized device space<br>
+
* eye space ---> clip space
normalized device space ---> window space<br>
+
* clip space ---> normalized device space
<br>
+
* normalized device space ---> window space
<br>
+
 
 +
So looking at the above, there are 5 steps. In GL, the modelview matrix is actually a 2 in 1 matrix. It is the camera matrix multiplied with the object's transform matrix. Therefore, there are actually 4 steps.
 +
 
 
Let's built a projection matrix.
 
Let's built a projection matrix.
 
   glLoadIdentity();
 
   glLoadIdentity();
Line 15: Line 17:
  
 
The resulting matrix looks like this
 
The resulting matrix looks like this
   [1.81, 0.00, 0.81, 0.00]
+
   [1.81, 0.00, -0.81, 0.00]
   [0.00, 1.81, 0.81, 0.00]
+
   [0.00, 10.0, 0.00, 0.00]
   [0.00, 0.00, -1.00, -2.00]
+
   [0.00, 0.00, -1.002, -2.002]
 
   [0.00, 0.00, -1.00, 0.00]
 
   [0.00, 0.00, -1.00, 0.00]
  
Line 33: Line 35:
 
   glViewport(0, 0, 800, 600);
 
   glViewport(0, 0, 800, 600);
  
The vertex you give to GL is considered to be in object space.<br>
+
== Step 1 : Getting to eye coordinates ==
Let's assume the values are [21.5, 58.6, -99.6, 1.0]<br>
+
The vertex you give to GL is considered to be in object space.
Notice that w=1.0<br>
+
 
When you transform a vertex by the modelview, the vertex is considered to be in eye space.<br>
+
Let's assume the values are [1.5, 1.6, -99.6, 1.0] Notice that w=1.0
Note: The modelview matrix is actually 2 matrices in 1. The world matrix which transforms from object space to world space and the view matrix which transforms from world to eye space.<br>
+
 
The vertex becomes [22.5, 60.6, -96.6, 1.0]<br>
+
When you transform a vertex by the modelview, the vertex is considered to be in eye space.
When you transform a vertex by the projection matrix, you get [-38.12, 31.14, 94.79, 96.59]. This is called clip coordinate.<br>
+
 
Then w inverse is computed : 1/96.59 = 0.0103520<br>
+
Note: The modelview matrix is actually 2 matrices in 1. The world matrix which transforms from object space to world space and the view matrix which transforms from world to eye space.
Each component is multiplied by the 1/w, you get [-0.394692, 0.322417, 0.981277, 1.0] This is called normalized device coordinates.<br>
+
 
Here, if z is from -1.0 to 1.0, then it is inside the znear and zfar clipping planes.<br>
+
The vertex becomes [2.5, 3.6, -96.6, 1.0]
Now the final stage of the transformation pipeline:<br>
+
 
The z is transformed to the 0.0 to 1.0 range. Anything outside this range gets clipped away. Notice that glDepthRange() has an effect here. By default, glDepthRange(0.0, 1.0)<br>
+
== Step 2 : Getting at clip coordinates ==
 +
When you transform a vertex by the projection matrix, you get [83.58, 36.0, 94.7914, 96.6]. This is called clip coordinate.
 +
 
 +
== Step 3 : Getting at normalized device coordinates ==
 +
Then w inverse is computed : 1/96.6 = 0.0103520
 +
 
 +
Each component is multiplied by the 1/w, you get [0.86522016, 0.372672, 0.9812785, 1.0] This is called normalized device coordinates.
 +
 
 +
Here, if z is from -1.0 to 1.0, then it is inside the znear and zfar clipping planes.
 +
 
 +
== Step 4 : Getting at window space ==
 +
Now the final stage of the transformation pipeline:
 +
 
 +
The z is transformed to the 0.0 to 1.0 range. Anything outside this range gets clipped away. Notice that glDepthRange() has an effect here. By default, glDepthRange(0.0, 1.0)
 +
 
 
The final operation looks like this
 
The final operation looks like this
   windowCoordinate[0]=(viewport[2] * x +(viewport[0] + viewport[2])) * 0.5;
+
   windowCoordinate[0] = (x * 0.5 + 0.5) * viewport[2] + viewport[0];
   windowCoordinate[1]=(viewport[3] * y +(viewport[1] + viewport[3])) * 0.5;
+
   windowCoordinate[1] = (y * 0.5 + 0.5) * viewport[3] + viewport[1];
   windowCoordinate[2]=(1.0 + z)*0.5;  //Convert to 0.0 to 1.0 range. Anything outside that ranges gets clipped.
+
   windowCoordinate[2] = (1.0 + z) * 0.5;  //Convert to 0.0 to 1.0 range. Anything outside that ranges gets clipped.
 +
 
 +
and the vertex will now be XYZ = [746.1, 411.8, 0.990639]
 +
 
 +
W doesn't matter.
 +
 
 +
== More Examples ==
 +
So in the example above, the z ended up being 0.990639. Since it is between 0.0 and 1.0, this vertex will not get clipped.
 +
 
 +
What if the vertex is [1.5, 1.6, 5.0, 1.0]?
 +
 
 +
eye space vertex would be [2.5, 3.6, 8.0, 1.0]
 +
 
 +
clip coordinates would be [-2.0, 36.0, -10.018, -8.0]
 +
 
 +
1/w is -0.125
 +
 
 +
normalized device coordinates would be [0.25, -4.5, 1.25225, 1.0]
 +
 
 +
window space would be XYZ = [500.0, -1050.0, 1.12613]. W doesn't matter.
 +
 
 +
Since y is below 0.0, this vertex would get clipped. Since z is above 1.0, this vertex would get clipped.
 +
 +
Another example :
 +
 
 +
What if the vertex is [1.5, 1.6, -1010.0, 1.0]? Notice that the z value is above the zfar value supplied to glFrustum (ignoring the negative sign).
 +
 
 +
eye space vertex would be [2.5, 3.6, -1007.0, 1.0]
 +
 
 +
clip coordinates would be [828.455, 36.0, 1007.01, 1007.00]
 +
 
 +
1/w is 0.000993
 +
 
 +
normalized device coordinates would be [0.822655815, 0.035748, 0.99996093, 1.0]
 +
 
 +
window space would be XYZ = [729.078, 310.725, 1.00001]. W doesn't matter.
  
and the vertex will now be [242.123, 396.725, 0.990639]<br>
+
The x and y value are fine but the z value is above 1.0, so this vertex would get clipped.
W doesn't matter.<br>
 

Revision as of 00:09, 11 April 2011

This page contains a small example that shows how a vertex is transformed.

This page will demonstrate:

  • object space ---> world space
  • world space ---> eye space
  • eye space ---> clip space
  • clip space ---> normalized device space
  • normalized device space ---> window space

So looking at the above, there are 5 steps. In GL, the modelview matrix is actually a 2 in 1 matrix. It is the camera matrix multiplied with the object's transform matrix. Therefore, there are actually 4 steps.

Let's built a projection matrix.

 glLoadIdentity();
 glFrustum(-0.1, 0.1, -0.1, 1.0, 1.0, 1000.0);

The resulting matrix looks like this

 [1.81, 0.00, -0.81, 0.00]
 [0.00, 10.0, 0.00, 0.00]
 [0.00, 0.00, -1.002, -2.002]
 [0.00, 0.00, -1.00, 0.00]

Let's built a very simple modelview matrix

 glLoadIdentity();
 glTranslatef(1.0, 2.0, 3.0);

The resulting matrix looks like this

 [1.0, 0.00, 0.00, 1.00]
 [0.00, 1.0, 0.00, 2.00]
 [0.00, 0.00, 1.00, 3.00]
 [0.00, 0.00, 0.00, 1.00]

and of course, the viewport also matters

 glViewport(0, 0, 800, 600);

Step 1 : Getting to eye coordinates

The vertex you give to GL is considered to be in object space.

Let's assume the values are [1.5, 1.6, -99.6, 1.0] Notice that w=1.0

When you transform a vertex by the modelview, the vertex is considered to be in eye space.

Note: The modelview matrix is actually 2 matrices in 1. The world matrix which transforms from object space to world space and the view matrix which transforms from world to eye space.

The vertex becomes [2.5, 3.6, -96.6, 1.0]

Step 2 : Getting at clip coordinates

When you transform a vertex by the projection matrix, you get [83.58, 36.0, 94.7914, 96.6]. This is called clip coordinate.

Step 3 : Getting at normalized device coordinates

Then w inverse is computed : 1/96.6 = 0.0103520

Each component is multiplied by the 1/w, you get [0.86522016, 0.372672, 0.9812785, 1.0] This is called normalized device coordinates.

Here, if z is from -1.0 to 1.0, then it is inside the znear and zfar clipping planes.

Step 4 : Getting at window space

Now the final stage of the transformation pipeline:

The z is transformed to the 0.0 to 1.0 range. Anything outside this range gets clipped away. Notice that glDepthRange() has an effect here. By default, glDepthRange(0.0, 1.0)

The final operation looks like this

 windowCoordinate[0] = (x * 0.5 + 0.5) * viewport[2] + viewport[0];
 windowCoordinate[1] = (y * 0.5 + 0.5) * viewport[3] + viewport[1];
 windowCoordinate[2] = (1.0 + z) * 0.5;   //Convert to 0.0 to 1.0 range. Anything outside that ranges gets clipped.

and the vertex will now be XYZ = [746.1, 411.8, 0.990639]

W doesn't matter.

More Examples

So in the example above, the z ended up being 0.990639. Since it is between 0.0 and 1.0, this vertex will not get clipped.

What if the vertex is [1.5, 1.6, 5.0, 1.0]?

eye space vertex would be [2.5, 3.6, 8.0, 1.0]

clip coordinates would be [-2.0, 36.0, -10.018, -8.0]

1/w is -0.125

normalized device coordinates would be [0.25, -4.5, 1.25225, 1.0]

window space would be XYZ = [500.0, -1050.0, 1.12613]. W doesn't matter.

Since y is below 0.0, this vertex would get clipped. Since z is above 1.0, this vertex would get clipped.

Another example :

What if the vertex is [1.5, 1.6, -1010.0, 1.0]? Notice that the z value is above the zfar value supplied to glFrustum (ignoring the negative sign).

eye space vertex would be [2.5, 3.6, -1007.0, 1.0]

clip coordinates would be [828.455, 36.0, 1007.01, 1007.00]

1/w is 0.000993

normalized device coordinates would be [0.822655815, 0.035748, 0.99996093, 1.0]

window space would be XYZ = [729.078, 310.725, 1.00001]. W doesn't matter.

The x and y value are fine but the z value is above 1.0, so this vertex would get clipped.