# Vertex Transformation

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

• 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.

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

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.