iPhone 3D Programming : Adding Depth and Realism - Examining the Depth Buffer

1/4/2011 4:12:34 PM
Before diving into lighting, let’s take a closer look at depth buffers, since we’ll need to add one to wireframe viewer.
Example 1. Depth buffer setup
// Create the depth buffer.
glGenRenderbuffersOES(1, &m_depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer);

// Create the framebuffer object; attach the depth and color buffers.
glGenFramebuffersOES(1, &m_framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_framebuffer);

// Bind the color buffer for rendering.
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);

glViewport(0, 0, width, height);


Why does HelloCone need a depth buffer when wireframe viewer does not? When the scene is composed of nothing but monochrome lines, we don’t care about the visibility problem; this means we don’t care which lines are obscured by other lines. HelloCone uses triangles rather than lines, so the visibility problem needs to be addressed. OpenGL uses the depth buffer to handle this problem efficiently.

Figure 1 depicts ModelViewer’s depth buffer in grayscale: white pixels are far away, black pixels are nearby. Even though users can’t see the depth buffer, OpenGL needs it for its rendering algorithm. If it didn’t have a depth buffer, you’d be forced to carefully order your draw calls from farthest to nearest.

Figure 1. Depth buffer in ModelViewer

OpenGL uses a technique called depth testing to solve the visibility problem. Suppose you were to render a red triangle directly in front of the camera and then draw a green triangle directly behind the red triangle. Even though the green triangle is drawn last, you’d want to the red triangle to be visible; the green triangle is said to be occluded. Here’s how it works: every rasterized pixel not only has its RGB values written to the color buffer but also has its Z value written to the depth buffer. OpenGL “rejects” occluded pixels by checking whether their Z value is greater than the Z value that’s already in the depth buffer. In pseudocode, the algorithm looks like this:

void WritePixel(x, y, z, color)
if (DepthTestDisabled || z < DepthBuffer[x, y]) {
DepthBuffer[x, y] = z;
ColorBuffer[x, y] = color;

1. Beware the Scourge of Depth Artifacts

Something to watch out for with depth buffers is Z-fighting, which is a visual artifact that occurs when overlapping triangles have depths that are too close to each other (see Figure 2).

Figure 2. Z-fighting in the Möbius strip

Recall that the projection matrix defines a viewing frustum bounded by six planes . The two planes that are perpendicular to the viewing direction are called the near plane and far plane. In ES 1.1, these planes are arguments to the glOrtho or glPerspective functions; in ES 2.0, they’re passed to a custom function like the mat4::Frustum method in the C++ vector library from the appendix.

It turns out that if the near plane is too close to the camera or if the far plane is too distant, this can cause precision issues that result in Z-fighting. However this is only one possible cause for Z-fighting; there are many more. Take a look at the following list of suggestions if you ever see artifacts like the ones in Figure 2.

Push out your near plane.

For perspective projections, having the near plane close to zero can be detrimental to precision.

Pull in your far plane.

Similarly, the far plane should still be pulled in as far as possible without clipping away portions of your scene.

Scale your scene smaller.

Try to avoid defining an astronomical-scale scene with huge extents.

Increase the bit width of your depth buffer.

All iPhones and iPod touches (at the time of this writing) support 16-bit and 24-bit depth formats. The bit width is determined according to the argument you pass to glRenderbufferStorageOES when allocating the depth buffer.

Are you accidentally rendering coplanar triangles?

The fault might not lie with OpenGL but with your application code. Perhaps your generated vertices are lying on the same Z plane because of a rounding error.

Do you really need depth testing in the first place?

In some cases you should probably disable depth testing anyway. For example, you don’t need it if you’re rendering a 2D heads-up display. Disabling the depth test can also boost performance.

  •  iPhone 3D Programming : HelloCone with Fixed Function
  •  iPhone 3D Programming : Vector Beautification with C++
  •  jQuery 1.3 : An image carousel
  •  jQuery 1.3 : Headline rotator
  •  Silverlight : Print a Document
  •  Silverlight : Capture a Webcam
  •  Silverlight : Make Your Application Run out of the Browser
  •  Silverlight : Put Content into a 3D Perspective
  •  Silverlight : Response to Timer Events on the UI Thread
  •  Silverlight : Build a Download and Playback Progress Bar
  •  Silverlight : Play a Video
  •  C# 4.0 : Add a Static Constructor and Initialization
  •  C# 4.0 : Add a Constructor
  •  .NET Compact Framework : Font Selection
  •  .NET Compact Framework : Drawing Text
  •  Programming the Service Bus
  •  WCF Services : Generics
  •  WCF Services : Delegates and Data Contracts
  •  WCF Services : Enumerations
  •  WCF Services : Versioning
    Top 20
    Windows Server 2003 : Creating and Configuring Application Directory Partitions
    Performance Management Tools in SQL Server 2008
    Algorithms for Compiler Design: SWITCH/CASE
    The Three-Step Approach to Security
    Worker Processes, Application Pools, and Identities in IIS 7
    WCF Services : Delegates and Data Contracts
    How an Access Control List Is Used
    Windows Server 2008 : Utilize System Center VMM
    E-mail Defenses in Windows Vista
    Algorithms for Compiler Design: ELIMINATING INDUCTION VARIABLES
    Resolve a Hostname to an IP Address
    Configuring Program Compatibility in Vista
    Algorithms for Compiler Design: STACK ALLOCATION
    Clustered Indexes in SQL Server 2008
    Setting Up a Silverlight Development System
    Non-Deterministic Finite Automata
    Protecting E-mail in Wondows 7
    Programming Hashing Algorithms (part 1) - The HashAlgorithm Class
    Configuring Networking for Laptops
    iPhone Programming : Creating a Table View