Frustum Culling optimization

Started by Lloydg, June 16, 2010, 12:54:00

Previous topic - Next topic

Lloydg

Hey all, I resently wrote a GameObject class, that all objects in a game would extend. In this class have a written a Frustum Culling method. Altho this does speed up the game (fps) I still think it could do with some optimization.

After profiling my code with NetBeans profiler it found my culling code as the biggest "hot spot".

This is my code.

package View;

import Model.Renderable;
import Model.Updateable;
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;

public abstract class GameObject implements Renderable, Updateable
{
    //STATIC VARIBLES
    private static int  nextObjectId    = 0;

    public static float halfWidth = 0.0f, halfHeight = 0.0f, near = 0.0f, far = 0.0f;
    public static float zcompW = 0.0f, zcompH = 0.0f;


    private int         objectId        = -1;
    private boolean     inFrustum       = true;
    protected float     cullingRadius   = 0.0f;
    protected Matrix4f  positionMatrix  = null;
    private boolean     matrixChanged   = false;
    private FloatBuffer postionMatrixBuffer = null;
    protected boolean   frustumCulling  = true;

    private FloatBuffer currentMatrixBuffer = null;
    float x, y, z;

    
    public GameObject()
    {
        objectId = nextObjectId++;
        positionMatrix = new Matrix4f();
        positionMatrix.setIdentity();

        //currentMatrix = new Matrix4f();

        postionMatrixBuffer = BufferUtils.createFloatBuffer(16);
        currentMatrixBuffer = BufferUtils.createFloatBuffer(16);
    }

    protected abstract void draw();

    public void render()
    {
        if (inFrustum)
        {
            GL11.glPushMatrix();
            GL11.glMultMatrix(postionMatrixBuffer);
            draw();
            GL11.glPopMatrix();
            //System.out.println("DRAWN");
        }
//        else
//        {
//            System.out.println("CULLED");
//        }
    }


    public void update(float dt)
    {
        if (matrixChanged) // update the position matrix buffer
        {
            positionMatrix.store(postionMatrixBuffer);
            postionMatrixBuffer.rewind();
            matrixChanged = false;
        }
        if (frustumCulling)
        {
            updateInFustum();
        }
    }

    private void updateInFustum()
    {

        GL11.glPushMatrix();
        GL11.glMultMatrix(postionMatrixBuffer);
        currentMatrixBuffer.rewind();
        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, currentMatrixBuffer);
        GL11.glPopMatrix();

        x = currentMatrixBuffer.get(12);
        y = currentMatrixBuffer.get(13);
        z = currentMatrixBuffer.get(14);

        zcompW = z * -halfWidth;

        if (z < far )
        {
            inFrustum = false;
            return;
        }
        if (z > near)
        {
            inFrustum = false;
            return;
        }

        inFrustum =
                (((x * near + zcompW) >  -cullingRadius) &&
                ((x * -near + zcompW) > -cullingRadius) &&
                ((y * -near + z * -halfHeight) > -cullingRadius) &&
                ((y * near + z * -halfHeight) > -cullingRadius));
    }

    protected void move(Vector3f v)
    {
        positionMatrix.translate(v);

        matrixChanged = true;
    }

    protected void move(float x, float y, float z)
    {
        move(new Vector3f(x,y,z));
    }

    protected void setIdentity()
    {
        positionMatrix.setIdentity();
        matrixChanged = true;
    }

    protected void rotate(float angle, float x, float y, float z)
    {
        positionMatrix.rotate(angle, new Vector3f(x,y,z).normalise(new Vector3f()));
        matrixChanged = true;
    }

    protected void scale(float x, float y, float z)
    {
        positionMatrix.scale(new Vector3f(x,y,z));
        matrixChanged = true;
    }
    
}


Whats your options on optimziting the this?

Thanks heaps, Lloyd

delt0r

If everything rendered is a game object, then each time things are updated you call your frustum culling code *for each game object*. Thats not efficient at all. On top of that you read matrices back from opengl. This is generally very slow... and combine that with doing it for each object.

Look up render passes and try to do things together... ie the "in frustum" method is perhaps better in the Game Object storage and be smart about what object to check.

Also I have a very rough frustum check in my code, since opengl clipping is pretty good/fast anyway. You don't want to waste too many cycles getting all accurate.
If you want a plot read a book and leave Hollywood out of it.

Lloydg

so would it be quicker to keep a Matrix4f of the what the model view would be, then use that instead of grabbing the matrix from opengl?
I only ever move the matrix with 1 camera so i could just store a Matrix4f of the cameras translation and use that to calculate?

Thanks, Lloyd

Rene

There's a lot of optimization potential. Some easy, some a lot harder. The easiest ones are methods like
protected void move(float x, float y, float z)
    {
        move(new Vector3f(x,y,z));
    }

It's best to avoid producing garbage if you can avoid it. In this case, add a translate() method to your matrix class which requires three float arguments instead of a Vector3f.
This saves you both the time for the object allocation and the garbage collection. Usually it's no big deal, but if this method is called really often it might save you some time.

Then there's the harder but more significant stuff, but I'll write about that a bit later. I just looked at the clock and I've got to run  ;)
When I am king, they shall not have bread and shelter only, but also teachings out of books, for a full belly is little worth where the mind is starved - Mark Twain