I have created an Orthographic projection camera for use in my simple opengl 2d renderer. Currently I have the problem that the calculated normalized device coordinates are wrong when I calculate them on the shader, but when I calculate them on the cpu I get the desired results.
I have created an Orthographic Projection matrix using the following formula:
2 / (right - left), 0, 0, -((right + left) / (right - left)),
0, 2 / (top - bottom), 0, -((top + bottom) / (top - bottom)),
0, 0, -2 / (zFar - zNear), -((zFar + zNear) / (zFar - zNear)),
0, 0, 0, 1
Where right = 1280, left = 0, top = 0, bottom = 720, zFar = 1.0 and zNear = -1.0.
So if I would create a rectangle using the following vertex positions:
float vertices[5 * 4] = {
//vertex pos tex pos
0.0f, 720.0f, 0.0f, 0.0f, 0.0f, //bottom left
1280.0f, 720.0f, 0.0f, 1.0f, 0.0f, //bottom right
1280.0f, 0.0f, 0.0f, 1.0f, 1.0f, //top right
0.0f, 0.0f, 0.0f, 0.0f, 1.0f // top left
};
It should result in a rectangle filling the entire screen.
To calculate the normalized device coordinates I use the following formula:
ViewProjectionMatrix * Transform * Position
In the vertex shader it looks like this:
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_TexCoord;
uniform mat4 u_ViewProjection;
uniform mat4 u_Transform;
uniform vec4 position;
out vec2 v_TexCoord;
void main()
{
v_TexCoord = a_TexCoord;
gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
}
u_ViewProjection is the above mentioned ViewProjection matrix, u_Transform is a transform matrix and is in this case a simple Identity matrix and a_Position is the vertex position.
Using the above values it results in the following render:
Now if I do the calculation on the cpu using the following code:
Mat4x4f transform = Mat4x4f::translate(Mat4x4f(1.0f), Vector3f(0.0f, 0.0f, 0.0f)) *
Mat4x4f::scale(Vector3f(1.0f, 1.0f, 1.0f));
// ViewProjectionMatrix * Transform * Position
Vector4f tl = camera.getViewProjectionMatrix() * transform * Vector4f(0.0f, 0.0f, 0.0f, 1.0f);
the transform is the same transform passed to u_Transform and the same for camera.getViewProjectionMatrix that is passed to u_ViewProjection.
Here I get the desired result: x = -1.0, y = 1.0 which should be the top left corner of the screen.
So my question... Am I doing something wrong in the shader or could it be something else causing this?
Edit 1
As said in the accepted answer the Projection matrix needed to be transposed, I came to this matrix by using the following source: https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/orthographic-projection-matrix.
Unfortunatly here they show an image implying it is colum major while it is actualy row major, see screen shot below:
You have to transpsoe the matrices, because OpenGL matrices are stored in Column-major order.
See The OpenGL Shading Language 4.6, 5.4.2 Vector and Matrix Constructors, page 108:
To initialize a matrix by specifying vectors or scalars, the components are assigned to the matrix elements in column-major order:
mat4(float, float, float, float, // first column float, float, float, float, // second column float, float, float, float, // third column float, float, float, float); // fourth column
The memory image of a 4*4 OpenGL matrix
c0 c1 c2 c3 c0 c1 c2 c3
[ Xx Yx Zx Tx ] [ 0 4 8 12 ]
[ Xy Yy Zy Ty ] [ 1 5 9 13 ]
[ Xz Yz Zz Tz ] [ 2 6 10 14 ]
[ 0 0 0 1 ] [ 3 7 11 15 ]
looks like this:
[ Xx, Xy, Xz, 0, Yx, Yy, Yz, 0, Zx, Zy, Zz, 0, Tx, Ty, Tz, 1 ]
So the view matrix has to be
2 / (right - left), 0, 0, 0,
0, 2 / (top - bottom), 0, 0,
0, 0, -2 / (zFar - zNear), 0,
-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((zFar + zNear) / (zFar - zNear)), 1
The other option would be to reverse the order of multiplication in the vertex shader:
gl_Position = vec4(a_Position, 1.0) * u_Transform * u_ViewProjection;
See GLSL Programming/Vector and Matrix Operations:
If a vector is multiplied to a matrix from the left, the result corresponds to multiplying a row vector from the left to the matrix. This corresponds to multiplying a column vector to the transposed matrix from the right: