Frustrum culling example: for basic translation.

hey guys. I wanted to post my approach to frustrum culling, in perspective mode.
The code takes into account a few assumptions, like the order of placement for the camera.

It can be made alot more robust, but I’v put in the main logic. In doesnt take into account any sorting of objects.


public class Frustrum {
  private static float xGradient, yGradient, distance, a1, b1, a2, b2, temp, x, y, z;


  public static void init(float fieldOfView, float aspectRatio) {
    xGradient = (float)Math.tan(Math.toRadians(fieldOfView)/2f);
    yGradient = (float)Math.tan(Math.toRadians(fieldOfView*aspectRatio)/2f);
  }

run at the start of program


  public static void update() {
    a1 = (float)Math.cos(-Math.toRadians(Camera.yRot));
    b1 = (float)Math.sin(-Math.toRadians(Camera.yRot));
    a2 = (float)Math.cos(-Math.toRadians(Camera.xRot));
    b2 = (float)Math.sin(-Math.toRadians(Camera.xRot));
  }

update should be called, when the camera rotation changes (or every cycle).

	
  //Returns mapObjects distance from the camera, if mapObject is not in frustrum will return 0
  public static float check(MapObject o, float radius) {
    //UN TRANSLATE CAMERA POSITION
    x = o.xPos - Camera.trueX;
    y = o.yPos - Camera.trueY;
    z = o.zPos - Camera.trueZ;
		
    //UN ROTATE CAMERA Y ROTATION
    temp = (x * a1) - (z * b1);
    z =    (x * b1) + (z * a1);
    x = temp;

    //UN ROTATE CAMERA X ROTATION
    temp = (z * b2) + (y * a2);
    z =    (z * a2) - (y * b2);
    y = temp;
    		
    //CHECK SIDE OF SCREEN BOOLEAN EQUATIONS
    if (y + radius < xGradient*z || x + radius < yGradient*z) return 0;
    z = -z;
    if (y - radius > xGradient*z || x - radius > yGradient*z) return 0;
    
    //* DISTANCE FROM CAMERA BOOLEAN CHECK - RADIAL VERSION - SLOWER!
    z = (float)Math.sqrt((x*x) + (y*y) + (z*z));
    if (z > Settings.fDistance || z < Settings.cDistance) return 0;

    //* DISTANCE FROM CAMERA BOOLEAN CHECK - FAST VERSION
    //if (z > Settings.fDistance || z < Settings.cDistance) return 0;

    return z;
  }
}

this is the actual frustrum code check.

ASSUMES CAMERA IS POSITION IN THE FOLLOWING WAY:
ratate(camera.xRot, 1, 0, 0);
ratate(camera.yRot, 0, 1, 0);
translate(-camera.x, -camera.y, -camera.z); //notice negative translation

Sure the order of rotation and translation can be changed depending on the camera placement.

Thx for this, interesting. Can you add some more about the var you init in the code please ? I’m sure if I can put it in my code. I’m looking for a way to place x.y.z my camera and look in the x.y.z right direction.

the init code variables refer to the variables used in the openGL function
gluPerspective(fieldOfView, aspectRatio, closeDistance, farDistance);
the number that is calculated is just a basic gradient value (used in a basic linear equation y = mx + c) m is the gradient.

this example is only for basic translations, and rotations. if doesnt really work if the rotations are all done in one call.

Basically what this code does, is positions the scene as if the camera were at position 0, 0, 0 with no rotation (camera normal, looking out at 0, 0, -1).
then the line equation test is run (y = mx + c) in this case there is no yIntercept © there fore the test run is:
y = mx, but to take into account the models/objects radius the test thats run is
y+radius = gradient * x. (this example checks if the object is ON the line, so less than or greather than signs are used to check if its in the screen)

this test is run for the top, bottom, left and right of the screen.

Assuming you camera is placed in the following way
translate(x, y, z);
rotate(yRot, 0, 1, 0);
here is a version that should work for you:


  public static void update() {
    a1 = (float)Math.cos(-Math.toRadians(Camera.yRot));
    b1 = (float)Math.sin(-Math.toRadians(Camera.yRot));
  }


  //Returns mapObjects distance from the camera, if mapObject is not in frustrum will return 0
  public static float check(MapObject o, float radius) {

    //UN ROTATE CAMERA Y ROTATION
    x = (o.xPos * a1) - (o.zPos * b1);
    z = (o.xPos * b1) + (o.zPos * a1);
    
    //UN TRANSLATE CAMERA POSITION
    x -= Camera.xPos;
    y = o.yPos - Camera.yPos;
    z -= Camera.zPos;

    //OR UNDO BOTH IN 1 STEP
    //x = (o.xPos * a1) - (o.zPos * b1) - Camera.xPos;
    //y = o.yPos - Camera.yPos;
    //z = (o.xPos * b1) + (o.zPos * a1) - Camera.zPos;

    //CHECK SIDE OF SCREEN BOOLEAN EQUATIONS
    if (y + radius < xGradient*z || x + radius < yGradient*z) return 0;
    z = -z;
    if (y - radius > xGradient*z || x - radius > yGradient*z) return 0;
    
    //* DISTANCE FROM CAMERA BOOLEAN CHECK - RADIAL VERSION - SLOWER!
    z = (float)Math.sqrt((x*x) + (y*y) + (z*z));
    if (z > farDistance || z < closeDistance) return 0;

    //* DISTANCE FROM CAMERA BOOLEAN CHECK - FAST VERSION
    //if (z > farDistance || z < closeDistance) return 0;

    return z;
  }