Setting Z-Buffer Bounds Automatically

Steve Hollasch

Why Set Bounds Automatically?

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.

Brute Force?

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:

The Formulas

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