I'm having some problems with my Frustum Culling and I want to debug it, so I'm trying to render it's planes, to see exatly the Frustum. But I'm using the Clip Coordinates to do the culling (like OpenGL pipeline do), but I dont know how to render a frustum, in another words, I dont know how to convert a frustum in Clip Coordinates to a "Frustum Mesh".

Actually to calculate the frustum I use this function:

glm::vec3 point = MVP * glm::vec4(-radius, -radius, -radius, 1.0f)) //leftTopPoint
return (point.x > -point.w) && //Inside left clipping pane
       (point.x < point.w) && //Inside right clipping pane
       (point.y > -point.w) && //Inside bottom clipping pane
       (point.y < point.w) && //Inside top clipping pane
       (point.z > -point.w) && //Inside near clipping pane
       (point.z < point.w); //Inside far clipping pane

Where MVP is a glm::mat4 of Projection * View * Model matrices.

This function is activated only when I press the left click of mouse, so I want to render the Frustum and see how it is.

Also I dont use a "lookAt" function to rotate the camera, I'm using Quaternions (dont know if that matters).

Sorry if it is a bit confusing, it's hard to explain. So I just need a tip or a orientation/example of how achive this.

Thanks for your attention.

  • \$\begingroup\$ But I'm using the Clip Coordinates to do the culling why is that? I would do it in world coordinates. If I understand correctly you are doing what we don't want openGL to do, worse yet on the CPU. \$\endgroup\$
    – concept3d
    Feb 26, 2014 at 22:48
  • 1
    \$\begingroup\$ Hmmm...you may be right, because even if I cull the vertex, the OpenGL doesnt do it, but I do....But Others methods seems to be the same, no? Also, I compute Projection * View just when camera changes and MVP just once per "Model", which saves some CPU.... \$\endgroup\$ Feb 26, 2014 at 22:51
  • \$\begingroup\$ You don't actually cull vertices. The common (and the more useful) practice is to cull whole meshes, usually by testing their bounding volumes intersection with the frustum. \$\endgroup\$
    – concept3d
    Feb 26, 2014 at 23:22
  • 1
    \$\begingroup\$ @concept3d I haven't though of doing so, but for me his approach to do frustum culling in screen space sounds very interesting. Calculating the transformation matrix on the CPU is no big hit and saves the GPU from doing it for every vertex separately. If I'm right, culling in screen space is much easier than testing against the frustum in world space. Update: Okay, the problem with this approach is that you can't cache the bounding box to test against because it changes with camera movement. \$\endgroup\$
    – danijar
    Feb 26, 2014 at 23:46
  • 1
    \$\begingroup\$ @concept3d You were right, the peformance using Clip Space to Frustum Culling is very bad. Thanks for your tip! \$\endgroup\$ Mar 1, 2014 at 14:32

1 Answer 1


I've done it by using a mix of Lighthouse3D tutorial, which I got by following the tip of @concept3d. My previous Frustum Culling routine was execute in about 12~16ms using Clip Space approach, but extracting planes from camera, I can execute it in 1~2ms....So, the peformance boost is awesome.

Here is my final code. Whenever my rotation/position changes, I update my frustum classe, like this:

localForward = glm::inverse(rotation) * -FORWARD; //Calculate the forward direction using the quaternion inverse and the inverse const direction (Always Z+).
relativeRight = glm::normalize(glm::cross(localForward, UP)); //This is relative because we use a const direction (Always Y+), so this isnt a local rotation.
localUp = glm::normalize(glm::cross(localForward, relativeRight)); //Now we calculate the local up based on local forward and relative right.

frustum->SetCameraInfo(position, localForward, relativeRight, localUp);

And to extract planes I just setup:

nearCenter = position + (forwardVector * nearDistance);
farCenter = position + (forwardVector * farDistance);

nearLeftTop     = nearCenter - rightVector * nearWidth + upVector * nearHeight;
nearLeftBottom  = nearCenter - rightVector * nearWidth - upVector * nearHeight;
nearRightTop    = nearCenter + rightVector * nearWidth + upVector * nearHeight;
nearRightBottom = nearCenter + rightVector * nearWidth - upVector * nearHeight;

farLeftTop      = farCenter - rightVector * farWidth + upVector * farHeight;
farLeftBottom   = farCenter - rightVector * farWidth - upVector * farHeight;
farRightTop     = farCenter + rightVector * farWidth + upVector * farHeight;
farRightBottom  = farCenter + rightVector * farWidth - upVector * farHeight;


            | \       / |
            |   +---+   |
            |   |   |   |
            |   +---+   |
            | /       \ |

planes[ePS_NEAR].SetPointAndNormal(nearCenter, forwardVector);
planes[ePS_FAR].SetPointAndNormal(farCenter, -forwardVector);

planes[ePS_TOP].CalcPointAndNormal(farLeftTop, (nearCenter + upVector * farWidth), farRightTop);
planes[ePS_BOTTOM].CalcPointAndNormal(farRightBottom, (nearCenter - upVector * nearWidth), farLeftBottom);

planes[ePS_LEFT].CalcPointAndNormal(farLeftBottom, (nearCenter - rightVector * nearWidth), farLeftTop);
planes[ePS_RIGHT].CalcPointAndNormal(farRightTop, (nearCenter + rightVector * nearWidth), farRightBottom);

Hope this help someone else. Thanks.

  • \$\begingroup\$ thank you for sharing this code but i think this give the normals of planes go inside the frustum and i think that they should go outside \$\endgroup\$
    – abdou
    Jun 8, 2021 at 16:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .