2
votes

Here's the vertex shader:

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;

void main(void)
{
    gl_Position = projection * view * model * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;
}

My understanding is that using various transformations, the model space is eventually turned to clip space, which is a box bound by each unit in each axis drawn directly to the viewport, i.e. something at (-1, 1,0) is at the top left of the viewport. When I remove all matrix transforms from the shader,

gl_Position = gl_Vertex;

and pass in, as the model, a simple quad

public Vector3[] verts = new Vector3[] {
    new Vector3(-1f, -1f, 0),
    new Vector3(1f, -1f, 0),
    new Vector3(1f, 1f, 0),
    new Vector3(-1f, 1f, 0),
};

public Vector2[] coords = new Vector2[] {
    new Vector2(0, 1f),
    new Vector2(1f, 1f),
    new Vector2(1f, 0f),
    new Vector2(0f, 0f),
};

public uint[] indices = new uint[] {
    0,1,2,
    0,2,3,
};

I get the expected full screen image. When I apply the transformations, the image appears as a small square in the centre of the screen, as you'd expect. The problem arises when I try to calculate the position of a vertex of the model in clip coordinates on the CPU:

public Vector4 testMult(Vector4 v, Matrix4 m)
{
    return new Vector4(
        m.M11 * v.X + m.M12 * v.Y + m.M13 * v.Z + m.M14 * v.W,
        m.M21 * v.X + m.M22 * v.Y + m.M23 * v.Z + m.M24 * v.W,
        m.M31 * v.X + m.M32 * v.Y + m.M33 * v.Z + m.M34 * v.W,
        m.M41 * v.X + m.M42 * v.Y + m.M43 * v.Z + m.M44 * v.W);
}

Matrix4 test = (GlobalDrawer.projectionMatrix * GlobalDrawer.viewMatrix) * modelMatrix;

Vector4 testv = (new Vector4(1f, 1f, 0, 1));
Console.WriteLine("Test Input: " + testv);
Console.WriteLine("Test Output: " + Vector4.Transform(testv, test));
Vector4 testv2 = testMult(testv, test);
Console.WriteLine("Test Output: " + testv2);
Console.WriteLine("Test Output division: " + testv2 / testv2.W);

(The matrices passed in are identical to the ones passed to the shader)

The program then proceeds to give output outside of clip space, and the division by W leads to divisions by 0:

Test Input: (1, 1, 0, 1)
Test Output: (0.9053301, 1.207107, -2.031746, 0)
Test Output: (0.9053301, 1.207107, -1, 0)
Test Output division: (Infinity, Infinity, -Infinity, NaN)

The matrices are created as follows:

projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, window.Width / (float)window.Height, 1.0f, 64.0f);
projectionMatrix =
(1.81066, 0, 0, 0)
(0, 2.414213, 0, 0)
(0, 0, -1.031746, -1)
(0, 0, -2.031746, 0)

viewMatrix = Matrix4.LookAt(new Vector3(0,0,4), -Vector3.UnitZ, Vector3.UnitY);
viewMatrix = 
(1, 0, 0, 0)
(0, 1, 0, 0)
(0, 0, 1, 0)
(0, 0, -4, 1)

modelMatrix = 
(0.5, 0  , 0  , 0)
(0  , 0.5, 0  , 0)
(0  , 0  , 1  , 0)
(0  , 0  , 0  , 1)

So, the question is why; what am I doing wrong?

1
Could you post how you created the three matrices (projection, view, and model) as those are quite important in figuring out what transformation you're doing.Laar
@Laar - I've added that to the question, thanks.AStupidNoob

1 Answers

3
votes

Edit (Adding real answer from comment)

Your OpenTK matrices are transposed by default. It looks to use row vectors instead of column vectors. Therefore you need to do the multiplication as (model * view * proj), not (proj * view * model). Either that or transpose all the matrices before uploading them.


Actually clip space is not from -1 to 1, but rather from -W to W, where W is the fourth component of the clip space vector.

What you're probably thinking of is called normalized device coodinates, which ranges from -1 to 1 on each axis. You get this value by dividing the X,Y, and Z coordinates of the clip space vector by the clip space W component. This division is called perspective division.

This is done behind the scenes after you pass the clip space coordinate to gl_Position.

Your clip space coordinate is 0 though, which doesn't seem to be correct to me.

There's some more detail here: OpenGL FAQ : Transformations.