How do I methodically choose the near clip plane distance for a perspective projection?

Kevin Reid picture Kevin Reid · Nov 12, 2011 · Viewed 9.6k times · Source

I have a 3D scene and a camera defined using gluPerspective. I have a fixed FOV, and I know the minimum distance of any geometry to the camera (it is a first-person view, so that is the minimum distance from the viewpoint to the character's collision volume).

How can I choose the farthest near clip plane (for the best depth buffer resolution) which will will not cause any clipping, no matter how the player moves and looks?

These distances are not simply equal because the corners of the near plane are farther from the origin than the center.

Answer

Kevin Reid picture Kevin Reid · Nov 12, 2011

Formula:

nearPlane = nearestApproachToPlayer / sqrt(1 + tan(fov/2)2 · (aspectRatio2 + 1)))

JavaScript code:

  var nearPlane = nearestApproachToPlayer 
                  / Math.sqrt(1 + Math.pow(Math.tan(fov/180*Math.PI/2), 2)
                                  * (Math.pow(aspectRatio, 2) + 1));

Derivation:

Geometrically, consider the pyramid whose base is the near clip plane and tip is the origin. Let nearPlane be the height of the pyramid, and w and h the width and height of the pyramid's base.

w = aspectRatio · h

The FOV determines the slope of the height-axis sides of the pyramid:

slope = tan(fov/2)

h/nearPlane = 2 tan(fov/2)

h/2 = nearPlane tan(fov/2)

Any corner point of the near clip plane is offset from the center of the clip plane by (w/2, h/2), so the distance is sqrt((w/2)2 + (h/2)2). The distance from the origin of this corner point is the hypotenuse of the right triangle formed by nearPlane and the former distance, so is sqrt((w/2)2 + (h/2)2 + nearPlane2).

We want that distance to the corner point to be equal to the closest approach of any geometry.

nearestApproachToPlayer = sqrt((w/2)2 + (h/2)2 + nearPlane2)

Applying straightforward algebra produces the formula given above.

I have not checked my algebra, but I have empirically tested the formula: if I multiply nearPlane by 1.1, then it produces a clip plane which is just a bit too far, for various aspect ratios. I have not tried different FOVs than 60°.