Modifying the Projection Matrix to Perform Oblique Near-Plane Clipping
Eric Lengyel • May 28, 2004
[Edit: This topic is covered in much greater detail in Foundations of Game Engine Development, Volume 2: Rendering.]
The following code modifies the OpenGL projection matrix so that the near plane of the standard view frustum is moved so that it coincides with a given arbitrary plane.
The far plane is adjusted so that the resulting view frustum has the best shape possible. This code assumes that the original projection matrix is a perspective projection
(standard or infinite). The clipPlane
parameter must be in camera-space coordinates, and its w-coordinate must be negative (corresponding to the camera
being on the negative side of the plane).
For algorithmic details, see “Oblique View Frustum Depth Projection and Clipping”, by Eric Lengyel. This technique is also described in Game Programming Gems 5, Section 2.6.
#include "TSVector4D.h" inline float sgn(float a) { if (a > 0.0F) return (1.0F); if (a < 0.0F) return (-1.0F); return (0.0F); } void ModifyProjectionMatrix(const Vector4D& clipPlane) { float matrix[16]; Vector4D q; // Grab the current projection matrix from OpenGL glGetFloatv(GL_PROJECTION_MATRIX, matrix); // Calculate the clip-space corner point opposite the clipping plane // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and // transform it into camera space by multiplying it // by the inverse of the projection matrix q.x = (sgn(clipPlane.x) + matrix[8]) / matrix[0]; q.y = (sgn(clipPlane.y) + matrix[9]) / matrix[5]; q.z = -1.0F; q.w = (1.0F + matrix[10]) / matrix[14]; // Calculate the scaled plane vector Vector4D c = clipPlane * (2.0F / Dot(clipPlane, q)); // Replace the third row of the projection matrix matrix[2] = c.x; matrix[6] = c.y; matrix[10] = c.z + 1.0F; matrix[14] = c.w; // Load it back into OpenGL glMatrixMode(GL_PROJECTION); glLoadMatrix(matrix); }