Let’s enhance the wireframe viewer by adding in
a depth buffer; this paves the way for converting the wireframes into
solid triangles. Before making any changes, use Finder to make a copy of
the folder that contains the SimpleWireframe project. Rename the folder to
ModelViewer, and then open the copy of the
SimpleWireframe project inside that folder. Select
Project→Rename, and
rename the project to ModelViewer.Open
RenderingEngine.ES1.cpp, and add GLuint
m_depthRenderbuffer; to the private: section
of the class declaration. Next, find the Initialize
method, and delete everything from the comment // Create the
framebuffer object to the
glBindRenderbufferOES call. Replace the code you
deleted with the code in Example 2.
Example 2. Adding depth to ES1::RenderingEngine::Initialize
// Extract width and height from the color buffer. int width, height; glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height);
// Create a depth buffer that has the same size as the color buffer. glGenRenderbuffersOES(1, &m_depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, width, height);
// Create the framebuffer object. GLuint framebuffer; glGenFramebuffersOES(1, &framebuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, m_colorRenderbuffer); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, m_depthRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
// Enable depth testing. glEnable(GL_DEPTH_TEST);
|
The ES 2.0 variant of Example 4-2 is almost exactly the same. Repeat the process in
that file, but remove all _OES and
OES suffixes.
Next, find the call to
glClear (in both rendering engines), and add a flag for
depth:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
At this point, you should be able to compile
and run, although depth testing doesn’t buy you anything yet since the app
is still rendering in wireframe.
By default, the depth buffer gets cleared to a
value of 1.0; this makes sense since you want all your pixels to initially
pass the depth test, and OpenGL clamps the maximum window-space Z
coordinate to 1.0. Incidentally, if you want to clear the depth buffer to
some other value, you can call glClearDepthf, similar
to glClearColor. You can even configure the depth test
itself using glDepthFunc. By default, pixels “win” if
their Z is less than the value in the depth buffer,
but you can change the test to any of these conditions:
GL_NEVER
Pixels never pass the depth test.
GL_ALWAYS
Pixels always pass the depth test.
GL_LESS
Pixels pass only if their Z value is less
than the Z value in the depth buffer. This is the default.
GL_LEQUAL
Pixels pass only if their Z value is less
than or equal to the Z value in the depth buffer.
GL_EQUAL
Pixels pass only if their Z value is
equal to the Z value in the depth buffer. This could be used to
create an infinitely thin slice of the scene.
GL_GREATER
Pixels pass only if their Z value is
greater than the Z value in the depth buffer.
GL_GEQUAL
Pixels pass only if their Z value is
greater than or equal to the Z value in the depth buffer.
GL_NOTEQUAL
Pixels pass only if their Z value is not
equal to the Z value in the depth buffer.
The flexibility of
glDepthFunc is a shining example of how OpenGL is often
configurable to an extent more than you really need. I personally admire
this type of design philosophy in an API; anything that is reasonably easy
to implement in hardware is exposed to the developer at a low level. This
makes the API forward-looking because it enables developers to dream up
unusual effects that the API designers did not necessarily anticipate.