Why are all of my vertices squished together after implementing matrices?

So I’ve started to switch a project over from using old deprecated OpenGL to the new core profile stuff. So while reimplementing the perspective camera, and then running the program, I noticed that nothing was being drawn, or everything was off the screen. So I opened up the debugger and saw this in the mesh view.

Why is it that all of those vertices are squished together on the z/x axis like that? All of the math for the making the perspective camera looks correct, as shown below.


package com.tinfoilboy.yagl.render;

import javax.vecmath.Matrix4f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3f;

import static org.lwjgl.opengl.GL11.*;

import com.tinfoilboy.yagl.MainApplication;

public class PerspectiveCamera extends Camera
{
	private float fieldOfView = 60.0f;

	private float aspectRatio = 0.0f;
	
	private float nearZ = 0.1f;

	private float farZ = 1000.0f;
	
	public Matrix4f projection = new Matrix4f();

	public Matrix4f view = new Matrix4f();
	
	public Vector3f position = new Vector3f();
	
	public Vector3f rotation = new Vector3f();
	
	public PerspectiveCamera()
	{
		this(75.0f, MainApplication.getWidth() / MainApplication.getHeight(), 0.1f, 1000.0f);
	}
	
	public PerspectiveCamera(float fieldOfView, float aspectRatio, float nearZ, float farZ)
	{
		this.fieldOfView = fieldOfView;
		this.aspectRatio = aspectRatio;
		this.nearZ = nearZ;
		this.farZ = farZ;
		init(false);
	}
	
	@Override
	protected void init(boolean isResize)
	{
		glViewport(0, 0, (int) MainApplication.getWidth(), (int) MainApplication.getHeight());
		setupProjectionMatrix();
	}
	
	@Override
	public void update()
	{
		view.set(0.0f);
		view.setTranslation(position);
		view.setRotation(new Quat4f(rotation.x, rotation.y, rotation.z, 1.0f));
		view.setScale(1.0f);
	}
	
	public float getAspectRatio()
	{
		return aspectRatio;
	}
	
	@Override
	public void resize(float width, float height)
	{
		aspectRatio = width / height;
		init(true);
	}
	
	public Matrix4f getProjection()
	{
		return projection;
	}
	
	public Matrix4f getView()
	{
		return view;
	}
	
	public float getFarZ()
	{
		return farZ;
	}
	
	private void setupProjectionMatrix()
	{
		float tanHalfFovy = (float) Math.tan(fieldOfView / 2.0f);
		projection.m00 = 1.0f / (aspectRatio * tanHalfFovy);
		projection.m11 = 1.0f / tanHalfFovy;
		projection.m22 = -(farZ + nearZ) / (farZ - nearZ);
		projection.m23 = -1.0f;
		projection.m32 = -(2.0f * farZ * nearZ) / (farZ - nearZ);
	}
}

Any help would be appreciated.

Hey tinfoilboy

As far as I can see, your code looks just fine to me. But may I recommend using Java Open Math Library a.k.a JOML instead of your current math classes? JOML is highly recommended by the LWJGL community and has some amazing math functions that could help you out a lot. I had these kind of problems as well and users recommended me to do the same. Doing so solved all my problems after screwing around for like 4 hours.

For example, right now you’re setting up a projection matrix manually by setting the rows and cols. With JOML, you can do it like this:


Matrix4f mProjection = new Matrix4f();
mProjection.perspective(60 / 180 * (float)Math.PI, 800.0f / 600.0f, 0.01f, 1000.0f);

I think your problems are related to those math classes of yours. I guess somewhere it does not really fits LWJGL’s needs and unintentionally returns wrong results. That was my situation and by switching to JOML I managed to solve it. I hope I’ve helped you with this!

Here is the link: https://github.com/JOML-CI

Sincerely,
TBJ

Ah that’s more like GLM from C++, I’ll switch to that seeing as how it’s more familiar to me, thanks! Also, those math classes weren’t mine. They were the old Java vecmath classes.

Okay so now when I use the JOML library, I can see that, if I use the perspective method with out converting to radians, it works fine, but as soon as I use the toRadians function, I get the insane projection value of this, as well as the fact that the view matrix is extremely off for some reason.

Also, here is the new perspective camera code, as well as the code that uploads the matrix to the shader (just the method cause the shader class is pretty long).

package com.tinfoilboy.yagl.render;

import static org.lwjgl.opengl.GL11.*;

import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;

import com.tinfoilboy.yagl.MainApplication;

public class PerspectiveCamera extends Camera
{
	private float fieldOfView = 60.0f;

	private float aspectRatio = 0.0f;
	
	private float nearZ = 0.1f;

	private float farZ = 1000.0f;
	
	public Matrix4f projection = new Matrix4f();

	public Matrix4f view = new Matrix4f();
	
	public Vector3f position = new Vector3f();
	
	public Quaternionf rotation = new Quaternionf(0.0f, 0.0f, 0.0f, 1.0f);
	
	public PerspectiveCamera()
	{
		this(45.0f, MainApplication.getWidth() / MainApplication.getHeight(), 0.01f, 1000.0f);
	}
	
	public PerspectiveCamera(float fieldOfView, float aspectRatio, float nearZ, float farZ)
	{
		this.fieldOfView = fieldOfView;
		this.aspectRatio = aspectRatio;
		this.nearZ = nearZ;
		this.farZ = farZ;
		init(false);
	}
	
	@Override
	protected void init(boolean isResize)
	{
		glViewport(0, 0, (int) MainApplication.getWidth(), (int) MainApplication.getHeight());
		setupProjectionMatrix();
		view.identity();
	}
	
	@Override
	public void update()
	{
		view.identity().translate(position).rotate(rotation);
	}
	
	public float getAspectRatio()
	{
		return aspectRatio;
	}
	
	@Override
	public void resize(float width, float height)
	{
		aspectRatio = width / height;
		init(true);
	}
	
	public Matrix4f getProjection()
	{
		return projection;
	}
	
	public Matrix4f getView()
	{
		return view;
	}
	
	public float getFarZ()
	{
		return farZ;
	}
	
	private void setupProjectionMatrix()
	{
		projection.perspective((float) Math.toRadians(fieldOfView), aspectRatio, nearZ, farZ);
	}
}
/**
 * Binds a 4x4 matrix to the shader.
 * */
public ShaderProgram setUniformMatrix4(String uniformName, Matrix4f mat4)
{
	int uniform = getUniformLocation(uniformName);
	if (uniform != -1)
	{
		FloatBuffer buf = BufferUtils.createFloatBuffer(16);
		mat4.get(buf);
		System.out.println(buf.get(0));
		glUniformMatrix4(uniform, false, buf);
	}
   return this;
}

The perspective method’s field of view parameter has to be in radians, so your result shouldn’t be happening. I do not know if the method toRadians work the same way as I’ve learnt because there is more than one way to convert degrees to radians, but try using this formula instead of a method and see if it makes any difference:


float fov = (float)(60 / 180 * Math.PI);

That being said, something else is bugging me. Please change this:


/**
 * Binds a 4x4 matrix to the shader.
 * */
public ShaderProgram setUniformMatrix4(String uniformName, Matrix4f mat4)
{
   int uniform = getUniformLocation(uniformName);
   if (uniform != -1)
   {
      FloatBuffer buf = BufferUtils.createFloatBuffer(16);
      mat4.get(buf);
      System.out.println(buf.get(0));
      glUniformMatrix4(uniform, false, buf);
   }
   return this;
}

Into this:


/**
 * Binds a 4x4 matrix to the shader.
 * */
public ShaderProgram setUniformMatrix4(String uniformName, Matrix4f mat4)
{
   int uniform = getUniformLocation(uniformName);
   if (uniform != -1)
   {
      FloatBuffer buf = BufferUtils.createFloatBuffer(16);
      mat4.get(buf);
      //System.out.println(buf.get(0));
      glUniformMatrix4(uniform, false, buf);
   }
   return this;
}

When you use the FloatBuffer’s get() method, you are actually reading the first item and move on to the next one. To explain this a bit easier. It is like reading a book with two persons. You read the first page and when you’re done you switch to the next one. The other person starts at page 2 and not at page 1. So like the FloatBuffer, you read a “page” and then give the “book” to the glUniformMatrix4 method who starts reading at “page” 2 when you actually want the glUniformMatrix4f to start at page 1. It could be that you are leaving out the first value (M11) in your matrix by accident.

I hope this will help you! Good luck!
-TBJ

A few things:

  • when building the view matrix like you do, first do the rotation and then the translation
  • if “position” is the position of your camera, then you have to translate by the negate of that vector, since in effect you are not translating the camera to that position, but the world to the “opposite”/negated position

Also, you seem to be updating your projection matrix based on when the window resizes. This call goes probably through [icode]resize()[/icode], which goes through [icode]init(true)[/icode] and that through [icode]setupProjectionMatrix()[/icode]. There you invoke the [icode]Matrix4f.perspective()[/icode] method, which is a post-multiplying method, as stated by the JavaDocs and the README.md on the GitHub page. So invoking it on a Matrix4f will first internally build the correct perspective matrix elements and then post-multiply that with the current matrix elements. What you may want to use instead is [icode]Matrix4f.setPerspective[/icode] which sets the matrix to a perspective projection matrix without post-multiplying it with the current matrix values.

Math.toRadians works exactly as expected.

This is wrong, well kind of. You are referring to [icode]get(void)[/icode], which indeed is a relative method. But the OP is using the [icode]get(int)[/icode] method, which belongs to the set of “absolute” methods, not modifying the buffer’s position. But otherwise nice explanation. :slight_smile:

So I tried those things, and now I get a flickering quad displaying on the screen, and the projection matrix values are still messed up, as shown below.

The new code is below, with the vertex shader as well.

Note: I removed the rotation part of the view code to see if that would help, it didn’t.

package com.tinfoilboy.yagl.render;

import static org.lwjgl.opengl.GL11.*;

import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;

import com.tinfoilboy.yagl.MainApplication;

public class PerspectiveCamera extends Camera
{
	private float fieldOfView = 60.0f;

	private float aspectRatio = 0.0f;
	
	private float nearZ = 0.1f;

	private float farZ = 1000.0f;
	
	public Matrix4f projection = new Matrix4f();

	public Matrix4f view = new Matrix4f();
	
	public Vector3f position = new Vector3f();
	
	public Quaternionf rotation = new Quaternionf(0.0f, 0.0f, 0.0f, 1.0f);
	
	public PerspectiveCamera()
	{
		this(75.0f, MainApplication.getWidth() / MainApplication.getHeight(), 0.01f, 1000.0f);
	}
	
	public PerspectiveCamera(float fieldOfView, float aspectRatio, float nearZ, float farZ)
	{
		this.fieldOfView = fieldOfView;
		this.aspectRatio = aspectRatio;
		this.nearZ = nearZ;
		this.farZ = farZ;
		init(false);
	}
	
	@Override
	protected void init(boolean isResize)
	{
		glViewport(0, 0, (int) MainApplication.getWidth(), (int) MainApplication.getHeight());
		setupProjectionMatrix();
		view.identity();
	}
	
	@Override
	public void update()
	{
		view.identity().setTranslation(position.negate());
	}
	
	public float getAspectRatio()
	{
		return aspectRatio;
	}
	
	@Override
	public void resize(float width, float height)
	{
		aspectRatio = width / height;
		init(true);
	}
	
	public Matrix4f getProjection()
	{
		return projection;
	}
	
	public Matrix4f getView()
	{
		return view;
	}
	
	public float getFarZ()
	{
		return farZ;
	}
	
	private void setupProjectionMatrix()
	{
		projection.setPerspective((float) Math.toRadians(fieldOfView), aspectRatio, nearZ, farZ);
	}
}
#version 330 core
layout(location = 0) in vec3 vert;
layout(location = 1) in vec4 color;
layout(location = 2) in vec2 texcoord;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
out vec2 textureCoordinate;

void main()
{
	gl_Position = projection * view * model * vec4(vert, 1.0);
	textureCoordinate = texcoord;
}

Please have a thorough read on the JavaDocs of the JOML methods you are using. Everything is explained there.
In particular, your use of Vector3f.negate() in the repeatedly called “update()” method.
If everything fails, there is always gluLookAt for the rescue, in the form of the Matrix4f.lookAt/setLookAt methods.