If you wish to compute the Z-buffer near & far planes automatically for a scene, you may run into a problem when your Z-buffer bounds are exact. Faces that lie exactly on the near or far clipping plane may be discarded either by comparison convention or by roundoff error.
This method widens the Z-volume such that only epsilon is lost off either end in perspective space. Note that widening the bounds by just adding and subtracting a fixed epsilon from the near and far planes directly will typically consume far too much Z resolution at your near plane, and not enough at your far plane.
To illustrate this, the following table shows the values for a given min and max Z depth, and sets hither and yon with a fixed epsilon of 1/1000th the distance from near to far. Note that the Z-buffer values are for a 16-bit Z-buffer (0–65535), and that the computed Z values are in [0,-1]:
Min Depth | Max Depth | Computed Hither | Computed Yon | Zbuffer Min | Zbuffer Max |
---|---|---|---|---|---|
-1 | -2 | -0.999000000 | -2.001000000 | 130.8738 | 65502.3306 |
-1 | -10 | -0.991000000 | -10.00900000 | 654.6306 | 65528.5184 |
-1 | -100 | -0.901000000 | -100.0990000 | 6546.8942 | 65534.4107 |
-0.1 | -100 | -0.000100000 | -100.0999000 | 65469.5304 | 65534.9999 |
-0.1 | -1000 | +0.899900000 | -1000.999900 | overflow | 65535.0589 |
Note that the near plane continues to waste Z space until the point that it overflows the perspective depth calculation (since the fixed delta causes it to go positive for large enough depth). In addition, note that the far plane is not positioned far enough away in the last two cases.
In constrast, the following table illustrates the formulas to calculate hither and yon such that the near and far planes are exactly 1.5 clicks (in Z-buffer coordinates) from the near and far planes:
Min Depth | Max Depth | Computed Hither | Computed Yon | Zbuffer Min | Zbuffer Max |
---|---|---|---|---|---|
-1 | -2 | -0.999988555 | -2.000045780 | 1.5000 | 65533.5000 |
-1 | -10 | -0.999979400 | -10.00206049 | 1.5000 | 65533.5000 |
-1 | -100 | -0.999977340 | -100.2271215 | 1.5000 | 65533.5000 |
-0.1 | -100 | -0.099997713 | -102.3401813 | 1.5000 | 65533.5000 |
-0.1 | -1000 | -0.099997711 | -1296.803111 | 1.5000 | 65533.5000 |
Perfect! Each point at the min depth lies exactly 1.5 clicks in from the front, and each point at the max depth lies 1.5 clicks shy of the far plane. Here's how it's done:
With this method, define epsilon to be the number of clicks in Z-buffer coordinates that you want to widen the Z space. In other words,
number of clicks epsilon = ---------------- (2bitdepth) - 1
Given the epsilon computed above, Znear (the nearest world-coordinate point in Z), and Zfar (the furthest world-coordinate point in Z), then the equations for hither and yon (the Z range to map to) are given as follows:
Znear * Zfar * (2*epsilon - 1) hither = -------------------------------- [Eq 1a] epsilon * (Znear + Zfar) - Zfar Znear * Zfar * (2*epsilon - 1) yon = -------------------------------- [Eq 1b] epsilon * (Znear + Zfar) - Znear
These formulas work whether you're in right-handed coordinates or in left-handed coordinates. The derivation changes slightly, but the results are identical.
We seek hither & yon such that
Zdepth(a) = -epsilon Zdepth(b) = -1 + epsilon [Eq 2]
where a is the closest Z value and b is the furthest (we are mapping Z to [0,-1]).
The perspective depth equation for this is
(Z - hither) * yon Zdepth(Z) = --------------------- [Eq 3] (yon - hither) * (-Z)
[Note that these are for Z mappings to [0,-1]. If you are mapping Z to the range [0,1] (usually if you're using left-handed coordinates), then negate equations [Eq 2] and [Eq 3]. You'll note in the following derivation that both forms yield identical solutions for hither and yon.]
Now we seek the values for hither and yon such that we get the Z depths for a and b as noted above in equation 1. For brevity, let e = epsilon, h = hither and y = yon. First we find hither:
(a-h)y (b-h)y --------- = -e --------- = -1 + e (y-h)(-a) (y-h)(-b) ae y y b(1-e) --- = --- --- = ------ a-h y-h y-h b-h ae b(1-e) --- = ------ a-h b-h ae(b-h) = b(a-h)(1-e) aeb - aeh = ab(1-e) - bh(1-e) aeb - ab(1-e) = aeh - bh(1-e) ab(e - (1-e)) = h(ae - b(1-e)) ab(e - (1-e)) = h(e(a+b) - b) ab (2e-1) h = ----------- [Eq 1a] e(a+b) - b
Finding yon in a similar manner, we get the nearly identical equation 1b. Again, these formulas for hither and yon can be used regardless of the handedness of the camera coordinate system (right-handed or left-handed).
Steve Hollasch / 1996 December 18