Using W-Buffers

Home | Up | Search | X-Zone News | Services | Book Support | Links | Feedback | Smalltalk MT | The Scrapyard | FAQ | Technical Articles

 

Using W-Buffers for Improved Depth Resolution

Written by Robert Dunlop
Microsoft DirectX MVP


Note:

 Code in this article was written for use with DirectX 7 under VC++ 6.0.  Some modification may be required for use in other development environments.

Related Articles of Interest:

Linearized Depth using Vertex Shaders

Introduction

As one will quickly find if working with a wide range of depths in a scene, the use of Z based depth can leave much to be desired.  While depth resolution near to the viewer may be quite good, the resolution rapidly degrades farther into the scene.

An alternative to this, supported through many available Direct3D compliant video adapters, is eye-relative depth buffers, known as W buffers.  We will take a look at the differences between these techniques of depth buffering, and learn how to implement W-buffers in Direct3D.

Non-Linearity of Z-Buffers

After transformation, the location of a vertex has been transformed to a position relative to the viewer.  Following transformation, the resulting 3D coordinates are divided by the results from the fourth column of the projection transform (W):

W = X M14 + Y M24 + Z M34 + M44
X1 = X / W
Y1 = Y / W
Z1 = Z / W

This provides the visual effect of perspective, by drawing points in the distance closer together.  However, it is in this operation that the issue arises.  The Z values are scaled to a range of 0.0 to 1.0, but the distribution of values is very non-linear.  For example, with a near clipping plane of 10 and a far clipping plane of 1000, the Z depth scaling is as shown below:

Z Input

Resulting Z1

10
20
100
200
500
1000

0.0
0.5
0.91
0.95
0.98
1.0

As you can see, half of the number space is used in the first 10 units of distance after the near plane.  At a distance of 100, over 90% of the range (and thus the resolution) has been used.

W Based Depth Buffering

W-Buffers offer an alternative to Z based depth buffers, and provide greatly improved linearity.  Rather than being based upon Z/W, depth is determined from W.  As W is directly proportional to the Z depth relative to the viewer, the result is a linear interpretation of depth. 

The resulting values are scaled to a range of 0.0 to 1.0, based upon the third column of the matrix.  The depth is scaled within the same range as Z, so that at the near plane Z=W=0.0, and at the far plane Z=W=1.0.

For such scaling to properly occur, the value of W must be equal to the input value of Z.  That is, the fourth column of the projection matrix must be equal to [0,0,1,0].  This is what is known as a W-friendly projection matrix, as shown below:

W

0

0

0

0

H

0

0

0

0

Q

1

0

0

-QZn

0

Where:

Zn

=

Near Clipping Plane

Zf

=

Far Clipping Plane

W

=

2 * Zn / Viewport Width

H

=

2 * Zn / Viewport Height

Q

=

Zf / (Zf - Zn)

Note that the helper functions provided with the D3D framework and the D3DX library generate W-friendly projection matrices.

Implementing a W-Buffer

Utilizing W based depth buffers is actually a trivial task.  A depth buffer is created and attached to the rendering surface, in the same manner as for a Z buffer.

Once a D3D device has been created, it must first be evaluated to determine if W-buffers are supported:

D3DDEVICEDESC7 caps;
lpDevice->GetCaps(&caps);
if (caps.dpcTriCaps.dwRasterCaps&D3DPRASTERCAPS_WBUFFER) {

If W-Buffers are supported, then depth buffering is enabled for W-Buffering:

    lpDevice->SetRenderState(D3DRENDERSTATE_ZENABLE,D3DZB_USEW);

Otherwise, normal Z-Buffering is enabled:

} else {
    lpDevice->SetRenderState(D3DRENDERSTATE_ZENABLE,D3DZB_TRUE);
}

A couple of final notes about using W-buffers.   Even if you are performing your own transformation, you must set a valid projection matrix, as the factors for Z scaling and offset will be utilized to scale W.  Also, be sure that your transformed vertices have valid RHW values, as W will be derived by taking the reciprocal of this value (1/RHW).

Finally, note that W based depth buffers are not necessarily the right choice for all applications.  In some cases, the increased resolution at near distances is needed, and Z-buffers are indicated.  To determine which is best for your application, I recommend that you test with both Z and W based depth buffers.

This site, created by DirectX MVP Robert Dunlop and aided by the work of other volunteers, provides a free on-line resource for DirectX programmers.

Special thanks to WWW.MVPS.ORG, for providing a permanent home for this site.

Visitors Since 1/1/2000: Hit Counter
Last updated: 07/26/05.