Build Frustum

frustum

Frustum is useful in the game collision or render

vec3f = vector (x , y ,z)

This is the frustum, there will be 6 planes and 8 points combine


struct Frustum
{
Plane planes[6];
vec3f corners[8];
};

This is the plane, there will be one vector three and one offset value combine


struct Plane
{
vec3f normal;
float offset;
};

 

for coding clear meaning, using enum to stand for individual corner

enum FrustumCorners{ FTL , FBL, FBR, FTR, NTL, NTR, NBR, NBL };
enum FrustumPlanes{ NEAR_PLANE = 0, FAR_PLANE, LEFT_PLANE, RIGHT_PLANE, TOP_PLANE, BOTTOM_PLANE };
  • This is the declaration of build frustum, we need to build based on camera position, because camera will move, so I use camera matrix to get the information.
  • Z is forward, X is right, Y is up

void BuildFrustum( Frustum& frustum, float fov, float nearDist, float farDist, float ratio, const matrix4f& camXform )
 {

//get near plane middle point and far plan middle based on the near distance and far distance
 vec3f nc = camXform.axis_pos - camXform.axis_z*nearDist;
 vec3f fc = camXform.axis_pos - camXform.axis_z*farDist;



//fov is the angle on x and z, so it can get the y axis difference
 float Hnear = 2 * tan(fov / 2)*nearDist;
 float Hfar = 2 * tan(fov / 2)*farDist;

// x axis difference can be got by ratio, because ratio definition is x / y , like our TV is 16:9
 float Wnear = Hnear* ratio;
 float Wfar = Hfar* ratio;

//so I can get the 8 corners vector value

frustum.corners[FTL] = fc + camXform.axis_y*Hfar*0.5 - camXform.axis_x * Wfar*0.5;
 frustum.corners[FBL] = fc - camXform.axis_y*Hfar*0.5 - camXform.axis_x * Wfar*0.5;
 frustum.corners[FBR] = fc - camXform.axis_y*Hfar*0.5 + camXform.axis_x * Wfar*0.5;
 frustum.corners[FTR] = fc + camXform.axis_y*Hfar*0.5 + camXform.axis_x * Wfar*0.5;
 frustum.corners[NTL] = nc + camXform.axis_y*Hnear*0.5 - camXform.axis_x * Wnear*0.5;
 frustum.corners[NTR] = nc + camXform.axis_y*Hnear*0.5 + camXform.axis_x * Wnear*0.5;
 frustum.corners[NBR] = nc - camXform.axis_y*Hnear*0.5 + camXform.axis_x * Wnear*0.5;
 frustum.corners[NBL] = nc - camXform.axis_y*Hnear*0.5 - camXform.axis_x * Wnear*0.5;

//Right now I can get the plane normal based on the two vector cross product, I use right hand system

//The offset can be got by dot product of the point and normalized normal of plane. In geometry, because it is the same as (point - origin ) dot (normalized normal), so I can do that.

//NEAR_PLANE
 cross_product(frustum.planes[NEAR_PLANE].normal, frustum.corners[NBL] - frustum.corners[NBR], frustum.corners[NTL] - frustum.corners[NBL]);
 frustum.planes[NEAR_PLANE].normal.normalize();
 frustum.planes[NEAR_PLANE].offset = dot_product(frustum.planes[NEAR_PLANE].normal, frustum.corners[NBL]);

//FAR_PLANE
 cross_product(frustum.planes[FAR_PLANE].normal, frustum.corners[FBR] - frustum.corners[FBL], frustum.corners[FTR] - frustum.corners[FBR]);
 frustum.planes[FAR_PLANE].normal.normalize();
 frustum.planes[FAR_PLANE].offset = dot_product(frustum.planes[FAR_PLANE].normal, frustum.corners[FBR]);
 //left_plane
 cross_product(frustum.planes[LEFT_PLANE].normal, frustum.corners[FBL] - frustum.corners[NBL], frustum.corners[FTL] - frustum.corners[FBL]);
 frustum.planes[LEFT_PLANE].normal.normalize();
 frustum.planes[LEFT_PLANE].offset = dot_product(frustum.planes[LEFT_PLANE].normal, frustum.corners[FBL]);

//RIGHT_PLANE
 cross_product(frustum.planes[RIGHT_PLANE].normal, frustum.corners[NBR] - frustum.corners[FBR], frustum.corners[NTR] - frustum.corners[NBR]);
 frustum.planes[RIGHT_PLANE].normal.normalize();
 frustum.planes[RIGHT_PLANE].offset = dot_product(frustum.planes[RIGHT_PLANE].normal, frustum.corners[NBR]);

//TOP_PLANE
 cross_product(frustum.planes[TOP_PLANE].normal, frustum.corners[NTR] - frustum.corners[FTR], frustum.corners[NTL] - frustum.corners[NTR]);
 frustum.planes[TOP_PLANE].normal.normalize();
 frustum.planes[TOP_PLANE].offset = dot_product(frustum.planes[TOP_PLANE].normal, frustum.corners[NTR]);

//BOTTOM_PLANE
 cross_product(frustum.planes[BOTTOM_PLANE].normal, frustum.corners[FBR] - frustum.corners[NBR], frustum.corners[FBL] - frustum.corners[FBR]);
 frustum.planes[BOTTOM_PLANE].normal.normalize();
 frustum.planes[BOTTOM_PLANE].offset = dot_product(frustum.planes[BOTTOM_PLANE].normal, frustum.corners[FBR]);

return ;
 }

 

That’s it, it can be used against other objects


bool FrustumToSphere(const Frustum& frustum, const Sphere& sphere);

bool FrustumToAABB(const Frustum& frustum, const AABB& aabb);

bool FrustumToCapsule(const Frustum& frustum, const Capsule& capsule);

To be continues..

Leave a comment