[Solved][LWJGL3]Can't get Frustum Culling to Work

I’ve tried lots of resources, such as the lighthouse3d tutorials (and more tutorials) and also Frustum classes that i’ve found on the internet. None of which have worked for me.

Note: before i show code i will note i am using JOML(Java OpenGl Math Library) for Vectors and Matrices, etc.

Here is the current Version that doesnt work(found it on internet and modified it): http://pastebin.com/CqtnXmag
Originally instead of:

Window.projectionMatrix.get(projectionBuffer);

it was:

glGetFloat(gl_projection_matrix, projectionbuffer)

and the same with the modelviewbuffer.

Window.projectionMatrix is created at the start of the window initialization class via:

public static Matrix4f updatePerspective(float fov, float aspect, float zNear, float zFar){
         Matrix4f matrix = new Matrix4f().identity();
		
         matrix.setPerspective(fov, aspect, zNear, zFar);
         perspective = matrix;
         return matrix;
}

and MatrixUtils.getmodelview() and matrixutils.getViewMatrix():

public static Matrix4f getViewMatrix(Camera camera){
		Vector3f cameraPos = camera.getTransform().getPosition();
		Quaternionf rotation = camera.getTransform().getRotation();
		
		Matrix4f viewMatrix = new Matrix4f().identity();
		//First do the rotation so camera rotates over its position
		viewMatrix.rotate((float)Math.toRadians(rotation.x), new Vector3f(1, 0, 0))
					.rotate((float)Math.toRadians(rotation.y), new Vector3f(0, 1, 0));
		//Then do the translation
		viewMatrix.translate(-cameraPos.x, -cameraPos.y, -cameraPos.z);
		return viewMatrix;
	}

	public static Matrix4f getModelViewMatrix(Transform transform, Matrix4f viewMatrix){
		Quaternionf rotation = transform.getRotation();
		Matrix4f modelViewMatrix = new Matrix4f().identity().translate(transform.getPosition())
						.rotateX((float)Math.toRadians(-rotation.x))
						.rotateY((float)Math.toRadians(-rotation.y))
						.rotateZ((float)Math.toRadians(-rotation.z))
						.scale(transform.getScale());
		Matrix4f viewCurr = new Matrix4f(viewMatrix);
		return viewCurr.mul(modelViewMatrix);
	}

Then (just to test) i am doing this every render call (for two cubes):

public void render(Window window, List<GameObject> renderList, Frustum frustum) {
		
		for(GameObject gameObject : renderList){
			frustum.calculateFrustum(camera);
			if(frustum.cubeInFrustum(gameObject.getTransform().getPosition().x, gameObject.getTransform().getPosition().y, gameObject.getTransform().getPosition().z, 1)){
				System.out.println("in frustum");
			}
			Matrix4f modelViewMatrix = MatrixUtils.getModelViewMatrix(gameObject.getTransform(), viewMatrix);
			shaderProgram.setUniform("modelViewMatrix", modelViewMatrix);
			shaderProgram.setUniform("material", gameObject.getMesh().getMaterial());
			gameObject.render(window, shaderProgram);
		}
	}

I don’t know whats wrong :frowning:

JOML also has a FrustumCuller built-in.
You can use that. It works correctly. But make sure to read its JavaDocs to know exactly what each method gets you (should be intuitive, though).

I tried that too but it didn’t work either.

It is a bit difficult to see what exactly you do there, but to perform frustum culling you need to feed the complete projection * view * model matrix to the culler. Not just view * model.

When i was using the frustumculler i was using:

frustumCuller.set(MatrixUtils.getModelViewMatrix(camera.getTransform(), MatrixUtils.getViewMatrix(camera)).mul(Window.projectionMatrix));

to set it. Again it didnt work?

Edit: then to check i do:

frustumCuller.set(MatrixUtils.getModelViewMatrix(camera.getTransform(), MatrixUtils.getViewMatrix(camera)).mul(Window.projectionMatrix));
		for(GameObject gameObject : renderList){
			if(frustumCuller.isPointInsideFrustum(gameObject.getTransform().getPosition())){
				System.out.println("in frustum");
			}
			Matrix4f modelViewMatrix = MatrixUtils.getModelViewMatrix(gameObject.getTransform(), viewMatrix);
			shaderProgram.setUniform("modelViewMatrix", modelViewMatrix);
...

You must multiply the projection before the view matrix.
It is always projection * view * model in that exact order. JOML’s mul() method right-multiplies the argument agains this.

I multiple the modelview matrix by projection matrix here(.mul(Window.projectionmatrix):

MatrixUtils.getModelViewMatrix(camera.getTransform(), MatrixUtils.getViewMatrix(camera)).mul(Window.projectionMatrix)

Again: You must do projection * modelview, and NOT modelview * projection. The order of multiplication is important.

Oh, one sec

I am being stupid, because it’s still not working :frowning: :-

public void render(Window window, List<GameObject> renderList, Frustum frustum) {
        frustumCuller.set(new Matrix4f(window.updatePerspective()).mul(MatrixUtils.getModelViewMatrix(camera.getTransform(), MatrixUtils.getViewMatrix(camera))));
		for(GameObject gameObject : renderList){
			if(frustumCuller.isPointInsideFrustum(gameObject.getTransform().getPosition())){
				System.out.println("in frustum");
			}
			Matrix4f modelViewMatrix = MatrixUtils.getModelViewMatrix(gameObject.getTransform(), viewMatrix);
			shaderProgram.setUniform("modelViewMatrix", modelViewMatrix);
			shaderProgram.setUniform("material", gameObject.getMesh().getMaterial());
			gameObject.render(window, shaderProgram);
		}
	}

Your getModelViewMatrix() also looks very suspicious (i.e. wrong).
You have some “Transform” class which stores the rotational aspect as a Quaternionf.
Though, you use the quaternion fields as if they were euler angles (which they aren’t).
You should use Matrix4f.rotate(Quaternionf) instead of the rotateX/rotateY/rotateZ if you already have the rotation as quaternion.

Changed it. No change.

Another problem is that you build the view/camera matrix inconsistently.
You use both getModelViewMatrix() as well as getViewMatrix() for it, which build it differently.

In the render() method you call getModelViewMatrix() with the camera transformation to build the camera matrix for frustum culling.
This is wrong. You cannot handle the camera like an object in the scene.
When building the modelview matrix for rendering you then differently use the viewmatrix previously built with getViewMatrix().

One advice: Please build the viewprojection matrix (projection * view) once correctly and then use this exact/same matrix object for both frustum culling and for rendering in your shader. Then only update a “model” matrix in your shader for rendering the individual objects.

Your a genius, cant thank you enough.

Actually since that the matrices were the problem could you also check if the same problem is affecting the rendering of my gui(nothing showing up):

I am trying to render some text with position set to 10, 10

public void GUIRender(GUIElement element){
		Matrix4f orthoMatrix = MatrixUtils.getOrthoProjectionMatrix(0, Window.WIDTH, Window.HEIGHT, 0);
		Mesh mesh = element.getMesh();
		Matrix4f projModelMatrix = MatrixUtils.getOrthoProjModelMatrix(element, orthoMatrix);
		guiShaderProgram.setUniform("projModelMatrix", projModelMatrix);
		guiShaderProgram.setUniform("color", mesh.getMaterial().getColour());
		if(mesh.getMaterial().getTexture() != null)guiShaderProgram.setUniform("hasTexture", 1);
		mesh.render();
	}
public static Matrix4f getOrthoProjectionMatrix(float left, float right, float bottom, float top){
		Matrix4f orthoMatrix = new Matrix4f().identity();
		orthoMatrix.setOrtho2D(left, right, bottom, top);
		return orthoMatrix;
	}
	
	public static Matrix4f getOrthoProjModelMatrix(GUIElement guiElement, Matrix4f ortho){
		Matrix4f orthoProjModelMatrix = new Matrix4f().translate(new Vector3f(guiElement.position, 0.0f)).scale(1);
		Matrix4f viewCurr = new Matrix4f(ortho);
		//return viewCurr.mul(orthoProjModelMatrix);
		return orthoProjModelMatrix.mul(viewCurr);
	}

I’ll instead give you an advice on how to improve your code quality and avoid having those bugs altogether. :slight_smile:

So, why don’t you have a method that only “applies” the projection transformation to a matrix, then have another method which only applies the “view” transformation to a matrix and then another method which only applies the model transformation. This way you can chain the transformations and keep separation of concern.

This is the model that the JOML API actually encourages. Not instantiating new matrices all over the place, copying matrices wildly from here to there and sometimes referencing method parameters while some other times referencing instance fields in methods. This all makes your code alot more complicated than need be.

So, ideally, your code would look like the code snippets on the JOML GitHub README.md. Clean invocations of perspective/ortho (or equivalent projection methods) followed by applying view/eye/camera transformations followed by model transformations.