Perspective projection matrix incorrect

I spent most of yesterday debugging because I couldn’t implement perspective projection. Anyway, I thought my issue was the fact that my matrix multiplication was incorrect, which I fixed (I then spent an hour this morning fixing orthographic projection). Now I’m having trouble getting perspective projection to work, which I’ve tried to debug but I’m not sure how to fix it.

Orthographic projection:


projection.overwrite(new float[] { 2f / width, 0f, 0f, 0f, 0f,
		2f / height, 0f, 0f, 0f, 0f, -2f, 0f,
		-((x * 2f + width) / width), -((y * 2f + height) / height),
		-1f, 1f });


t = top, b = bottom, l = left, r = right

Debugging results (it works):

Perspective projection:


		projection.overwrite(new float[] { (2f * zNear) / width, 0f, 0f, 0f,
				0f, (2f * zNear) / height, 0f, 0f, (2f * x + width) / width,
				(2f * y + height) / height, -(-zFar + zNear) / (zFar - zNear),
				-1f, 0f, 0f, -(2f * zFar * zNear) / (zFar - zNear), 0f });


t = top, b = bottom, l = left, r = right, n = zNear, f = zFar

Debugging results - n = 1, f = 100 (nothing is displayed):

What could the problem be? I’m not really sure what I’m doing wrong. I’ve tried translating the Z coordinate and extending the far pane, but I see nothing. I’m clearing the depth buffer and I tried enabling depth testing. None of those things worked.

EDIT: I think it must be something to do with the Z coordinate, since when I translate it, the W coordinate changes but nothing is displayed.

Because we don’t see the code around this one, perhaps try disabling other stuffs like lighting, texture…

EDIT : here is a site that gives a well explanation on perspective projection, if that could help.

I’ve not got anything else enabled. The code:

The viewport is being set as the width and the height of the screen.
This is the render method (it uses my LWJGL wrapper/library). This is the same for orthographic projection (except for clearing depth buffer):


GL.glClearColor(colour);
GL.glClear(Buffer.COLOR_DEPTH); // combined colour and depth buffer
program.attach(); // simply calls glUseProgram
program.setUniformMatrix4x4("mvp", camera.update()); // calls setUniformMatrix4, the matrix isn't transposed
vao.attach();
vao.render(Primitive.TRIANGLE_STRIP, 4); // calls glDrawArrays
VertexArrayObject.detach();
ProgramObject.detach();

I’m updating my view*Projection uniform variable with this method (you can see the values of the matrices (column major) in my OP), this is the same for orthographic projection:


	public Matrix4 update() {
		return scale.copy().multiply(rotation).multiply(translation)
				.multiply(projection);
	}

This is how I’m setting the data for the attribute (it shouldn’t really matter since orthographic projection works and uses the same data):


data = FloatBufferIO.create(0f, 0f, 100f, 0f, 0f, 100f, 100f, 100f);
vertices = new BufferObject(Target.ARRAY_BUFFER, data,
		Usage.STATIC_DRAW);

vao = new VertexArrayObject();
vao.attach();
vertices.attach();
vao.formatAttributeData(program.getAttributeIndex("position"), 2, // enables the attribute & calls glVertexAttribPointer
		DataType.SIGNED_FLOAT, false, 8, 0);
VertexArrayObject.detach();

When resized (and when the camera is created), this is called in the PerspectiveCamera class:


projection.overwrite(new float[] { (2f * zNear) / width, 0f, 0f, 0f,
		0f, (2f * zNear) / height, 0f, 0f, (2f * x + width) / width,
		(2f * y + height) / height, -(-zFar + zNear) / (zFar - zNear),
		-1f, 0f, 0f, -(2f * zFar * zNear) / (zFar - zNear), 0f });

Sorry if it’s unclear. If you want to see anything else just ask.

Edit: This is my matrix multiplication method (it seems to work correctly, judging by the debugging results):


		float m00 = (components[0] * matrix.components[0])
				+ (components[1] * matrix.components[4])
				+ (components[2] * matrix.components[8])
				+ (components[3] * matrix.components[12]);
		float m01 = (components[0] * matrix.components[1])
				+ (components[1] * matrix.components[5])
				+ (components[2] * matrix.components[9])
				+ (components[3] * matrix.components[13]);
		float m02 = (components[0] * matrix.components[2])
				+ (components[1] * matrix.components[6])
				+ (components[2] * matrix.components[10])
				+ (components[3] * matrix.components[14]);
		float m03 = (components[0] * matrix.components[3])
				+ (components[1] * matrix.components[7])
				+ (components[2] * matrix.components[11])
				+ (components[3] * matrix.components[15]);
		float m10 = (components[4] * matrix.components[0])
				+ (components[5] * matrix.components[4])
				+ (components[6] * matrix.components[8])
				+ (components[7] * matrix.components[12]);
		float m11 = (components[4] * matrix.components[1])
				+ (components[5] * matrix.components[5])
				+ (components[6] * matrix.components[9])
				+ (components[7] * matrix.components[13]);
		float m12 = (components[4] * matrix.components[2])
				+ (components[5] * matrix.components[6])
				+ (components[6] * matrix.components[10])
				+ (components[7] * matrix.components[14]);
		float m13 = (components[4] * matrix.components[3])
				+ (components[5] * matrix.components[7])
				+ (components[6] * matrix.components[11])
				+ (components[7] * matrix.components[15]);
		float m20 = (components[8] * matrix.components[0])
				+ (components[9] * matrix.components[4])
				+ (components[10] * matrix.components[8])
				+ (components[11] * matrix.components[12]);
		float m21 = (components[8] * matrix.components[1])
				+ (components[9] * matrix.components[5])
				+ (components[10] * matrix.components[9])
				+ (components[11] * matrix.components[13]);
		float m22 = (components[8] * matrix.components[2])
				+ (components[9] * matrix.components[6])
				+ (components[10] * matrix.components[10])
				+ (components[11] * matrix.components[14]);
		float m23 = (components[8] * matrix.components[3])
				+ (components[9] * matrix.components[7])
				+ (components[10] * matrix.components[11])
				+ (components[11] * matrix.components[15]);
		float m30 = (components[12] * matrix.components[0])
				+ (components[13] * matrix.components[4])
				+ (components[14] * matrix.components[8])
				+ (components[15] * matrix.components[12]);
		float m31 = (components[12] * matrix.components[1])
				+ (components[13] * matrix.components[5])
				+ (components[14] * matrix.components[9])
				+ (components[15] * matrix.components[13]);
		float m32 = (components[12] * matrix.components[2])
				+ (components[13] * matrix.components[6])
				+ (components[14] * matrix.components[10])
				+ (components[15] * matrix.components[14]);
		float m33 = (components[12] * matrix.components[3])
				+ (components[13] * matrix.components[7])
				+ (components[14] * matrix.components[11])
				+ (components[15] * matrix.components[15]);
		components[0] = m00;
		components[1] = m01;
		components[2] = m02;
		components[3] = m03;
		components[4] = m10;
		components[5] = m11;
		components[6] = m12;
		components[7] = m13;
		components[8] = m20;
		components[9] = m21;
		components[10] = m22;
		components[11] = m23;
		components[12] = m30;
		components[13] = m31;
		components[14] = m32;
		components[15] = m33;

Edit2: I’ll try transposing the projection matrix, since the page you linked me to has the exact same matrix transposed. It doesn’t display, however this is the result:

Edit3: Never-mind, that was based on row major order. It gives the exact same matrix. I think that the issue must be related to something else.

:clue: --> :emo: --> :cranky: --> :expressionless: --> :o --> ;D --> >:( >:( >:( >:( --> 8)

That’s the last 60 seconds of my life. ^^

The problem: -(-zFar + zNear) / (zFar - zNear).
The solution: -(zFar + zNear) / (zFar - zNear).

FFS@@~#’#;’#;’@~:@{:[’;[p’;[p#@:@:@:@:{l:[] >:(#;{@~:~{@:?:@:@:@:’;[p];[;]-p]=;[]=+{}= >:(=’[];[#’;];’[#;
Ten hours of debugging just for that…

Edit: It requires me to translate the camera 1 on the Z axis. Should I add 1 to -(2f * zFar * zNear) / (zFar - zNear)?

Well done !
(I would not have imagined being so useless :emo: ;D)