Projection matrix isn't calculated correctly

I’ve been trying to convert over to “modern” OpenGL, and one of the first steps I took was to try to figure out how to use matrices and specifically model the glm library. I honestly had to research and stitch code together a lot, so that’s probably my issue. But I don’t know enough about matrices to even try to guess what’s wrong!

So, I tried to create a function similar to the glm::perspective one. It is quite simply this:

public static Matrix4f perspective(float fovy, float aspect, float zNear, float zFar) {
		final float halfFov = (float) Math.toRadians((fovy / 2.0f));
		final float range = (float) Math.tan(halfFov) * zNear;
		final float left = -range * aspect;
		final float right = range * aspect;
		final float bottom = -range;
		final float top = range;
		
		Matrix4f res = new Matrix4f();
		res.m00 = (2 * zNear) / (right - left);
		res.m11 = (2f * zNear) / (top - bottom);
		res.m22 = -(zFar + zNear) / (zFar - zNear);
		res.m23 = -1f;
		res.m32 = -(2f * zFar * zNear) / (zFar - zNear);
		
		return res;
	}

And then I tried to create a glm::lookAt function:

public static Matrix4f lookAt(Vector3f eye, Vector3f center, Vector3f up) {
		Vector3f f = new Vector3f(), u = new Vector3f(), s = new Vector3f();
		Vector3f.sub(center, eye, f);
		up.normalise(u);
		Vector3f cross = Vector3f.cross(f, u, s);
		cross.normalise(s);
		Vector3f.cross(s, f, u);
		
		Matrix4f res = new Matrix4f();
		res.m00 = s.x;
		res.m10 = s.y;
		res.m20 = s.z;
		res.m01 = u.x;
		res.m11 = u.y;
		res.m21 = u.z;
		res.m02 = -f.x;
		res.m12 = -f.y;
		res.m22 = -f.z;
		
		return res;
	}

I then use it like this:

		projection = MatrixUtils.perspective(90.0f, 4.0f / 3.0f, 0.1f, 100.0f);
		view = MatrixUtils.lookAt(new Vector3f(0, 0, 0), new Vector3f(0, 0, -1), new Vector3f(0, 1, 0));
		model = new Matrix4f();

(Model being a “identity” matrix.)

I then pass all those matrices into my shaders, and I multiply them together:

layout(location = 0) in vec3 pos;

uniform mat4 projection, view, model;

void main()
{
	gl_Position = (projection * view * model) * vec4(pos, 1);	
}

My issue is that I try to use the Matrix4f.translate function to translate the geometry. But, instead of actually translating, the vertices simply “rotate” around a point, which actually seems to be the “Z-axis”. Here’s a picture to clarify what I mean:

This is the square being drawn “unmodified (no translations)”:

And then, I just add this line of code:

	Matrix4f.translate(new Vector2f(1, 0), model, model);

Which results in this:

I expected the square to just move over to the left of the screen, but it looks as if it has rotated somehow and stretched itself. Here is the entire class:


public class World {

	private Matrix4f projection, view, model;
	private Shader shader;
	private int vertexBuffer = 0, vbo = 0;

	float[] vData = {
			// Left bottom triangle
			-0.5f, 0.5f, 0f,
			-0.5f, -0.5f, 0f,
			0.5f, -0.5f, 0f,
			// Right top triangle
			0.5f, -0.5f, 0f,
			0.5f, 0.5f, 0f,
			-0.5f, 0.5f, 0f
	};

	private FloatBuffer buffer;
	
	public World() {
		projection = MatrixUtils.perspective(90.0f, 4.0f / 3.0f, 0.1f, 100.0f);
		view = MatrixUtils.lookAt(new Vector3f(0, 0, 0), new Vector3f(0, 0, -1), new Vector3f(0, 1, 0));
		model = new Matrix4f();
		Matrix4f.translate(new Vector2f(1, 0), model, model);
		shader = new Shader("/shaders/basic.vert", "/shaders/basic.frag");

		shader.addUniform("projection");
		shader.addUniform("view");
		shader.addUniform("model");

		buffer = Utils.createFloatBuffer(vData.length);
		buffer.put(vData);
		buffer.flip();
		
		vertexBuffer = GL30.glGenVertexArrays();
		GL30.glBindVertexArray(vertexBuffer);
		
		vbo = GL15.glGenBuffers();
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
		
		GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
		
		GL30.glBindVertexArray(0);
	}

	public void update() {
	}

	public void render() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
		shader.use();
		shader.setUniformMat("projection", projection);
		shader.setUniformMat("view", view);
		shader.setUniformMat("model", model);
		
		GL30.glBindVertexArray(vertexBuffer);
		GL20.glEnableVertexAttribArray(0);
		
		GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, 2 * 3);
		
		GL20.glDisableVertexAttribArray(0);
		GL30.glBindVertexArray(0);
	}
}

(Please excuse the mess!)
Does anyone have idea what I could be doing wrong?

Looks like a y-axis rotation to me.

Have you tried drawing a box?

That might make it easier to see for certain what’s going on.

I did, the box took up the entire screen though. I tried setting the “center” vector of the lookAt function to move backwards (bad terminology) so I could see more of the box, but nothing “moved”. I can set the z component of the center vector to anything but 0 and I will get a screen full of red pretty much. But if it is set to 0, then the box isn’t rendered at all.

Try having a look at this.

I haven’t personally gone into the programmable pipeline with matrices yet, so apart from general debugging, I’m not of much use.

I’ve tried looking at that, I’ll have a look over it again…

To anyone that reads this (and you Heroes), is it worth it to bother with my own matrix system?

It’s probably good practice too, unless you can and want to use libraries that do it for you.

I’m still using fixed-function matrix stuff because it works well enough for me, but at some point in the future, (probably after LWJGL 3.0 when I have to rewrite some of my utility code anyway) I’ll do some matrix stuff.

I would use a library but I can’t really find one, which is frustrating. GLM for C/C++ is really nice, but there seems to be no equivalent for Java. Anyway, hopefully someone more mathematically inclined than I am will come along and notice my obvious mistake…

How about isolating the two functions (perspective and lookat) to work out which is doing something wrong?

They go hand in hand, I don’t think I can use one without the other because the projection of the vertices on the screen would be screwed up. Not to mention I really don’t know what I’m looking for :frowning: I know how some of the code works, but I don’t understand the underlying concept well enough to actually figure out what I did wrong. It is my issue, but I was just wondering if anyone here could point out something stupidly obvious!

Your look-at matrix is incorrect. first of all it only seems to handle rotation, not translation. (it is a 3x3 rotation matrix with no inscribed translation). and even then it handles it incorrectly

try this look at matrix pseudo code



zaxis = normalize(Position - Eye)
xaxis = normalize(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)

RotMatrix
{
 xaxis.x                                      yaxis.x                             -zaxis.x                               0   
 xaxis.y                                      yaxis.y                            -zaxis.y                              0
 xaxis.z                                      yaxis.z                             -zaxis.z                              0
    0                                              0                                     0                                   1
}

transMatrix
{
  1   0     0      -eye.x
  0   1     0      -eye.y
  0   0     1      -eye.z
  0   0     0         1
}

lookAtMatrix = transMatrix * rotMatrix
//If you rotate first then translate do it like this, otherwise flip these


keep in mind openGL is column major, so m23 is the 3rd column 4th row.

your matrix looks something like this

xaxis.x xaxis.y xaxis.z 0
up.x up.y up.z 0
-zaxis.x -zaxis.y -zaxis.z 0
0 0 0 1

making your own matrix, glm type binding will teach you a lot and give you a lot of power in openGL, so i highly recommend it. I’ve done it in 2D and in 3D and it opens up huge possibilities and is a good stepping stone into openGL 3.3+

BTW, lemme know if this is for a 2D engine, if it is there are lots of unneeded calculations here.

[edit x2]
fixed some dumb mistakes i made

Thank you! No, this is for 3D :slight_smile:

So exactly how do I implement those new matrices with my code? Is it literally just multiplying the rotation and translation matrices together? That’s it?

To be anal. column major refers to storage order…linear algebra is linear algebra, so if you’re doing all the lifting yourself you can use either of the transposed versions as long as you’re consistent.

understood, correct me if i’m wrong but aren’t the vectors in openGL automatically row vectors, so you’d have to use mat1x4 instead of vec4? Seems like a lot of extra work :slight_smile:

@opiop to get the matrix with both rotation and translation you multiply the two matricies i mentioned before together. I made a slight change in the post that you should look at. Keep in mind the matrix on the right of the multiplication is implemented first so makes sure you translate then rotate or rotate then translate depending on what you want to do.

But that’s it Lion? Sorry, I’m reading a math primer right now but I haven’t found anything about the view matrix yet… I just need those two matrices and that’s it?

Those 2 matrices are the rotational and translational components of the view matrix. So yes you multiply them both together to get the view matrix.

Alright thank you, I’ll test that out when I get home! Thank you very much :slight_smile:

I might be wrong, but I want to think GLSL treats a vector as either a column or row matrix depending on order.

Well, I tried your code Lion, it may be working (I don’t know if it really is!), but here is what I did:


public static Matrix4f lookAt(Vector3f eye, Vector3f center, Vector3f up) {
		Vector3f xaxis = new Vector3f(), yaxis = new Vector3f(), zaxis = new Vector3f();
		
		Vector3f PosEye = new Vector3f();
		Vector3f.sub(center, eye, PosEye);
		PosEye.normalise(zaxis);

		Vector3f.cross(up, zaxis, xaxis).normalise();
		Vector3f.cross(zaxis, xaxis, yaxis);
		
		Matrix4f RotMatrix = new Matrix4f();
		RotMatrix.m00 = xaxis.x;
		RotMatrix.m01 = yaxis.x;
		RotMatrix.m02 = -zaxis.x;
		RotMatrix.m03 = 0;
		RotMatrix.m10 = xaxis.y;
		RotMatrix.m11 = yaxis.y;
		RotMatrix.m12 = -zaxis.y;
		RotMatrix.m13 = 0;
		RotMatrix.m20 = xaxis.z;
		RotMatrix.m21 = yaxis.z;
		RotMatrix.m22 = -zaxis.z;
		RotMatrix.m23 = 0;
		RotMatrix.m30 = 0;
		RotMatrix.m31 = 0;
		RotMatrix.m32 = 0;
		RotMatrix.m33 = 1;
		
		Matrix4f TransMatrix = new Matrix4f();
		TransMatrix.m00 = 1;
		TransMatrix.m01 = 0;
		TransMatrix.m02 = 0;
		TransMatrix.m03 = -eye.x;
		TransMatrix.m10 = 0;
		TransMatrix.m11 = 1;
		TransMatrix.m12 = 0;
		TransMatrix.m13 = -eye.y;
		TransMatrix.m20 = 0;
		TransMatrix.m21 = 0;
		TransMatrix.m22 = 1;
		TransMatrix.m23 = -eye.z;
		TransMatrix.m30 = 0;
		TransMatrix.m31 = 0;
		TransMatrix.m32 = 0;
		TransMatrix.m33 = 1;
		
		return Matrix4f.mul(TransMatrix, RotMatrix, new Matrix4f());
	}

The square still “stretches” when translating :frowning:

Also, what is the “Position” in your code? Isn’t “eye” the position?