Using Depth Buffers

A depth buffer (often referred to as a z-buffer or a w-buffer) is how Direct3D stores "depth" information for rendering. This depth information is used during rasterization to determine how pixels block (occlude) each other. Currently, our application has no depth buffer associated with it, so no pixels are occluded during rasterization. However, we have no pixels that are occluded anyway, so let's try to draw a few more cubes that will actually overlap some of our existing cubes. Add the following DrawBox calls to the end of our existing DrawBox calls:

 DrawBox(angle / (float)Math.PI, angle / (float)Math.PI * 2.0f, angle / (float)Math.PI /     4.0f, 0.0f, (float)Math.Cos(angle), (float)Math.Sin(angle)); DrawBox(angle / (float)Math.PI, angle / (float)Math.PI / 2.0f, angle / (float)Math.PI *     4.0f, 5.0f, (float)Math.Sin(angle), (float)Math.Cos(angle)); DrawBox(angle / (float)Math.PI, angle / (float)Math.PI / 2.0f, angle / (float)Math.PI /     2.0f, -5.0f, (float)Math.Cos(angle), (float)Math.Sin(angle)); 

All we are really doing here is having three extra cubes spin around the three center horizontal cubes. Running this application, you can easily see the cubes overlapping, but you can't visually see where one cube ends and the other begins. It appears as if the cubes are simply a blob. This is where a depth buffer comes in handy.

Adding a depth buffer to our application is actually quite an easy task. Do you remember the presentation parameters we passed in to our device constructor? Well, this is where we include our depth buffer information. There are two new parameters we will need to fill out to include a depth buffer with our device:

 public Microsoft.DirectX.Direct3D.DepthFormat AutoDepthStencilFormat [get,  set] public bool EnableAutoDepthStencil [get,  set] 

SHOP TALK: SAVING MEMORY WITH INDEX BUFFERS

So how exactly does using an index buffer save memory for our application? Let's compare the relatively simple cube applications, both with and without using the index buffer. In the first scenario, we created a vertex buffer holding 32 vertices of type CustomVertex.PositionColored. This structure happens to be 16 bytes (4 bytes each for x, y, z, and color). Multiply this size by the number of vertices, and you can see our vertex data consists of 576 bytes of data.

Now, compare this with the index buffer method. We only use 8 vertices (of the same type), so our vertex data size is 128 bytes. However, we are also storing our index data as well, so what is the size of that? We are using short indices (2 bytes each) and we are using 36 of them. So our index data alone is 72 bytes, combined with our vertex data we have a total size of 200 bytes.

Compare that to our original size of 576 bytes, and we have a remarkable 65% reduction in memory usage. Extrapolate these numbers out for very large scenes, and the possible memory saved using index buffers can be quite substantial.

Setting "EnableAutoDepthStencil" to true will turn on the depth buffer for your device, using the depth format specified in the AutoDepthStencilFormat member. Valid values of the DepthFormat enumeration for this member are listed in Table 4.1:

Table 4.1. Possible Depth Formats

VALUE

DESCRIPTION

D16

A 16-bit z-buffer bit depth.

D32

A 32-bit z-buffer bit depth.

D16Lockable

A 16-bit z-buffer bit depth that is lockable.

D32FLockable

A lockable format where depth value is represented by a standard IEEE floating point number.

D15S1

A 16-bit z-buffer bit depth using 15 bits for depth channel, with the last bit used for the stencil channel (stencil channels will be discussed later).

D24S8

A 32-bit z-buffer bit depth using 24 bits for depth channel, with the remaining 8 bits used for the stencil channel.

D24X8

A 32-bit z-buffer bit depth using 24 bits for depth channel, with the remaining 8 bits ignored.

D24X4S4

A 32-bit z-buffer bit depth using 24 bits for depth channel, with 4 bits used for the stencil channel, and the remaining 4 bits ignored.

D24FS8

A non-lockable format that contains 24 points of depth (as a floating point) and 8 bits for the stencil channel.

SHOP TALK: PICKING THE RIGHT DEPTH BUFFER

Nearly every graphics card on the market today supports a z-buffer; however, depending on the circumstances, using this depth buffer can have its drawbacks. When calculating the depth of a pixel, Direct3D will place the pixel somewhere in the z-buffer range (normally from 0.0f to 1.0f), but this placement is rarely uniform across the entire range. The ratio of the near and far plane directly affects the distribution pattern of your z-buffer.

For example, if your near plane is 1.0f, and your far plane is 100.0f, 90% of the range will be used in the first 10% of your depth buffer. If you had a large "outdoor" scene, it wouldn't be uncommon to have much larger far planes. In the previous example, if your far plane was 1000.0f, 98% of the range would be used in the first 2% of the depth buffer. This could cause "artifacts" on distant objects, which may or may not matter in your application.

Using a w-buffer depth buffer eliminates this problem, but has its own downfalls as well. It's possible for artifacts to appear on near objects rather than distant objects when using a w-buffer. Also, it's worth noting that there isn't as much support in graphics cards for w-buffers as there is for z-buffers.

One last comment on depth buffers. For greater performance when rendering using depth buffers, it's best to render items from front (highest z) to back (lowest z). During scene rasterization, Direct3D can quickly reject a pixel that is already occluded and skip the drawing completely. This is naturally not the case when we're rendering data with alpha components, but since we haven't gotten that far yet, we'll skip that until later.

Larger depth buffers can naturally store much more depth data, at the expense of performance. Unless you know you need a very large depth buffer, stick with smaller values. Most modern graphics cards will support a minimum of a 16-bit depth buffer, so add that to the present parameters structure:

 presentParams.EnableAutoDepthStencil = true; presentParams.AutoDepthStencilFormat = DepthFormat.D16; 

Perfect, now our device has a depth buffer. Let's see what difference it makes in our application. Go ahead and run it now.

Well, something must be broken because that isn't what we were supposed to see. What happened to our cubes? Why did adding a depth buffer to our device suddenly cause all of our rendering to break? Interestingly enough, it's because our depth buffer was never "cleared," so it was in an invalid state. We are already clearing our device, and it's an easy fix to clear our depth buffer at the same time. Modify your clear call as follows:

 device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.CornflowerBlue, 1.0f, 0); 

Running the application now produces desired results. You can easily see how the cubes are separated, and the depth buffer is now functioning normally.



Managed DirectX 9 Graphics and Game Programming, Kick Start
Managed DirectX 9 Kick Start: Graphics and Game Programming
ISBN: B003D7JUW6
EAN: N/A
Year: 2002
Pages: 180
Authors: Tom Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net