3D Graphics with OpenGL ES and M3G- P24 potx

10 193 0
3D Graphics with OpenGL ES and M3G- P24 potx

Đang tải... (xem toàn văn)

Thông tin tài liệu

214 OPENGL ES RASTERIZATION AND FRAGMENT PROCESSING CHAPTER 9 9.5 PIXEL TESTS Toward the end of the graphics pipeline the pixels are subjected to a sequence of tests. The first of the tests is the scissor test which allows only pixels within a rectangular box to pass. This is followed by alpha, stencil, and depth tests. All of these tests compare one component of the pixel, i.e., the alpha, stencil, or depth component, to a reference value. The comparison function can be set to always pass the pixel (GL_ALWAYS), never pass it (GL_NEVER), or pass depending on the relative value of the component with respect to the reference value (GL_LESS, GL_LEQUAL, GL_GREATER, GL_GEQUAL, GL_EQUAL,orGL_NOTEQUAL). 9.5.1 SCISSORING The scissor test, if enabled, allows only pixels within the scissor box to be modified by drawing commands. The scissor box is defined by calling void glScissor(GLint x, GLint y, GLint width, GLint height) By default, the scissor test is not enabled. The scissor box is defined by giving the lower left corner, followed by the width and height in pixels. For example, glEnable( GL_SCISSOR_TEST ); glScissor( 10, 5, 100, 200 ); defines a scissor box starting from (10, 5) and extending to (110, 205). If the scissor box is not enabled, the result is the same as if the box covered the entire window. Changing the scissor box may require flushing the graphics pipeline, so it is advisable to set it up only in the beginning of the frame. 9.5.2 ALPHA TEST The next test after the scissor test is the alpha test. It discards incoming fragments based on a comparison between the fragment’s alpha value and a reference value. This can be useful when combined with alpha blending, as it can beused to skip the rest of the pipeline when completely transparent texels are encountered in a texture map. Alpha test is a rela- tively cheap operation even in software implementations of OpenGL ES, and if a texture contains many discardable texels, using it can even accelerate the rendering . void glAlphaFunc(GLenum func, GLclampf ref) void glAlphaFuncx(GLenum func, GLclampx ref) is used for selecting the comparison function and the reference alpha value. The parameter func should be one of the tests on page 214, while ref specifies the reference value. The reference alpha value is clamped to [0, 1] where 0 indicates completely transparent and 1 fully opaque. To allow skipping the fully transparent pixels call SECTION 9.5 PIXEL TESTS 215 glEnable( GL_ALPHA_TEST ); glAlphaFunc( GL_NOTEQUAL, 0.0f ); Here is a longer example for the alpha test. If you have a drawing routine that has both opaque and translucent objects, you should first render the opaque ones before blending the translucent ones on top of them. During the first pass depth writing should be enabled, during the second pass it should be disabled, though the depth test itself should be executed. Now transparent objects behind solids will not be drawn, but the ones in front of them will all blend in. To guarantee correct blending the transparent objects should be sorted and drawn in back-to-front order. glEnable( GL_DEPTH_TEST ); /* enable depth test */ glDepthFunc( GL_LESS ); /* use default depth func */ glDepthMask( GL_TRUE ); /* allow z-buffer update */ glEnable( GL_ALPHA_TEST ); /* enable alpha test */ glAlphaFunc( GL_GEQUAL, 0.999f ); /* draw only solids */ myDrawFunc(); /* draw the scene */ glDepthMask( GL_FALSE ); /* disable z-buffer update */ glAlphaFunc( GL_LESS, 0.999f ); /* draw only translucent surfaces */ glEnable( GL_BLEND ); /* set up blending */ glBlendFunc( GL_SRC_ALPHA, /* typical blending mode */ GL_ONE_MINUS_SRC_ALPHA ); myDrawFunc(); /* draw the scene, again */ glDisable( GL_ALPHA_TEST ); /* reset to typical state */ glDisable( GL_BLEND ); /* reset to typical state */ glDepthMask( GL_TRUE ); /* reset to typical state */ 9.5.3 STENCIL TEST Stencil testing, in its basic form, is a more gener al scissoring function. One can first draw an arbitrary 2D shape, or stencil, into the stencil buffer, and then incoming fragments are kept or discarded depending on whether they fall within the stencil shape. However, if your stencil shape is a box, it is much cheaper to use the scissor test instead. Uses for stencil buffer, in addition to the arbitrary-shaped scissor areas, include many a dvanced algorithms, such as drawing line drawings with hidden lines removed, drawing arbitrary polygons with holes and indentations, and creating volumetric lighting effects and shad- ows. However, this versatile tool has a high cost: it needs its own buffer, and therefore not all implementations support stenciling. To find out whether the currently active EGL surface has a stencil buffer, and how deep it is, you can query for GL_STENCIL_BITS (8 is a typical number of stencil bits). Of course, at first you should ask for an EGL config that supports stencil buffers as described in Chapter 11. The stencil test function is set like the alpha test. It needs to be enabled with glEnable ( GL_STENCIL_TEST ), and you need to select one of the tests on page 214 (the initial mode is GL_ALWAYS) by calling void glStencilFunc(GLenum func, GLint ref, GLuint mask) 216 OPENGL ES RASTERIZATION AND FRAGMENT PROCESSING CHAPTER 9 The reference value ref is an integer value [0, 2 s − 1] where s is the number of bits in the stencil buffer. The default reference value is 0. The third argument is mask,whichis ANDed with both the reference value and the stored stencil value before the comparison test (the default mask has all bits set to one). If there is no stencil buffer, the stencil test always passes. The values of the stencil buffer are set using void glStencilOp(GLenum sfail, GLenum zfail, GLenum zpass) which instructs how the stencil buffer is updated based on whether the stencil test fails, the depth test fails, or whether the depth test passes. The following update functions are supported GL_KEEP leaves the existing stencil buffer contents unmodified GL_ZERO sets the stencil buffer value to zero GL_REPLACE copies the stencil reference value to the buffer GL_INCR increments the stencil buffer value by one (clamps to 2 s − 1) GL_DECR decrements the stencil buffer value by one (clamps to 0) GL_INVERT performs a bitwise inversion to the stencil buffer value The initial state corresponds to glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ) which never modifies the stencil buffer. Here is a simple stencil example, which draws an irregular stencil shape and then uses that to delimit later draw ing. glEnable( GL_STENCIL_TEST ); glClearStencil( 0 ); /* prepare to clear to 0 */ glClear( GL_STENCIL_BUFFER_BIT ); /* actually clear */ glStencilFunc( GL_ALWAYS, 1, 1 ); /* set ref and mask to 1 */ glStencilOp( GL_REPLACE, GL_REPLACE, /* set to one where you draw */ GL_REPLACE ); /* draw the stencil shape */ glStencilOp( GL_KEEP, GL_KEEP, /* do not modify further */ GL_KEEP ); glStencilFunc( GL_EQUAL, 1, 1 ); /* draw inside the stencil */ /* your drawing routine */ glStencilFunc( GL_NOTEQUAL, 1, 1 ); /* draw outside the stencil */ /* your drawing routine */ glDisable( GL_STENCIL_TEST ); The following is a more complex example that uses stencil buffers for volumetric shadows [Hei91]. The idea is to first draw the scene with only ambient lighting. For the parts of the scene that do not get any direct lighting, that is, are in the shadow, that is all there is to do. The shadow volumes are modeled as geometry, and are used to update the stencil SECTION 9.5 PIXEL TESTS 217 buffer. If the front surface of a shadow volume is between the camera and object, that object is potentially in the shadow. Every such shadow will increase the stencil buffer by one. However, if the back surface of the shadow volume is also between camera and the object, then that volume does not reach up to the object, and the stencil buffer is decreased by one. In the end, pixels with stencil values equaling zero are not in shadow, and should be redrawn with full lighting. Note that this example makes several assumptions of light directions and the view frustum setup, and only works for simple cases, as it is meant to illustrate mostly the stencil buffer processing. /* prepare to draw the scene with ambient lights, store depth */ glDisable( GL_STENCIL_TEST ); glEnable( GL_DEPTH_TEST ); glDepthFunc( GL_LESS ); glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); glDepthMask( GL_TRUE ); glCullFace( GL_BACK ); draw_scene_with_ambient_lights(); /* now don’t touch color or depth */ glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); glDepthMask( GL_FALSE ); /* Render front triangles only */ glEnable( GL_CULL_FACE ); glCullFace( GL_BACK ); /* INCRement stencil where depth test passes */ glEnable( GL_STENCIL_TEST ); glStencilMask( 0xffffffff ); glStencilFunc( GL_ALWAYS, 0x00000000, 0xffffffff ); glStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); draw_shadow_volumes(); /* render back triangles only */ glCullFace( GL_FRONT ); /* DECRement stencil where depth test passes */ glStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); draw_shadow_volumes(); /* pass stencil test ONLY when stencil is zero (not in shadow) */ glStencilFunc( GL_EQUAL, 0x00000000, 0xffffffff ); /* process only visible surface front pixels */ glCullFace( GL_BACK ); glDepthFunc( GL_EQUAL ); /* redraw color buffer on surviving pixels */ glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); draw_scene_with_normal_light(); 218 OPENGL ES RASTERIZATION AND FRAGMENT PROCESSING CHAPTER 9 9.5.4 DEPTH TESTING Depth testing is the final test in the OpenGL ES fragment pipeline. It is used for sorting the primitives at each pixel based on their distance from the camera. Typically we want the closest object to cover the ones farther away. However, some algorithms exist that need other depth orderings. Depth test is globally turned on or off by calling glEnable or glDisable with the symbolic constant GL_DEPTH_TEST. void glDepthFunc(GLenum func) selects between the eight depth comparison functions on page 214. This function is used to compare a fragment’s depth value against the one already stored in the depth buffer at the same pixel location. The default function is GL_LESS. The extended shadow volume example in the previous section also illustrates the use of the depth test. When the scene is drawn for the first time, the basic comparison mode glDepthFunc( GL_LESS ) is used to discard all the fragments but the ones closest to the camera. When it is drawn for the second time, we switch the comparison function to glDepthFunc( GL_EQUAL ) so that only those fragments that are visible are retained. If the mode would still be GL_LESS no fragments would survive the depth test on the second round. Polygon offsets Polygon offsets are used for modifying the depth values of triangles. This is a useful feature for, e.g., rendering decals on top of flat surfaces. With polygon offsets you can make sure that the decal is in front of the surface, but not so far that a noticeable gap would show between them. The feature can be turned on or off using glEnable or glDisable with GL_POLYGON_OFFSET_FILL. void glPolygonOffset(GLfloat factor, GLfloat units) void glPolygonOffsetx(GLfloat factor, GLfixed units) defines the scale factor and units that are used to modify the fragment’s depth value. Both are initially set to 0. See Section 3.5.1 for a more detailed discussion of polygon offsets. 9.6 APPLYING FRAGMENTS TO THE COLOR BUFFER Once a fragment has been fully processed, it is applied to the color buffer. Three alterna- tive mechanisms exist: the fragment can be copied directly to replace the correspond- ing pixel in the color buffer, the fragment can be blended with the color buffer, or a logical operation may be applied to combine the fragment with the color buffer. Finally, some frame buffer channels might be masked so that writes are not performed to them. SECTION 9.6 APPLYING FRAGMENTS TO THE COLOR BUFFER 219 9.6.1 BLENDING Blending takes the incoming fragment color (with texturing and fog already applied) and the color that already exists in the frame buffer, and uses them to come up with a new color to be stored in the frame buffer. Blending was described in Section 3.5.2. Blending can be turned on and off by using glEnable and glDisable with the symbolic constant GL_BLEND. Blending is disabled by default. When enabled, a blend operation multiplies the incoming, or source, fr a gment color C s by a source blend factor F s , and the pixel in the color buffer, or destination color C d , by a destination blend factor F d , multiplies and adds component-wise C s F s + C d F d , clamps it to [0,1], and stores the result into the color buffer. void glBlendFunc(GLenum sfactor, GLenum dfactor) sets up the source and destination blend factors. The following table lists the allowed tokens, describes the actual factors, and tells whether they are permissible to be used as a source or a destination factor, or both. Token Factor src dst GL_ZERO (0, 0, 0, 0) √√ GL_ONE (1, 1, 1, 1) √√ GL_SRC_COLOR (R s , G s , B s , A s ) √ GL_ONE_MINUS_SRC_COLOR (1, 1, 1, 1) − (R s , G s , B s , A s ) √ GL_DST_COLOR (R d , G d , B d , A d ) √ GL_ONE_MINUS_DST_COLOR (1, 1, 1, 1) − (R d , G d , B d , A d ) √ GL_SRC_ALPHA (A s , A s , A s , A s ) √√ GL_ONE_MINUS_SRC_ALPHA (1, 1, 1, 1) − (A s , A s , A s , A s ) √√ GL_DST_ALPHA (A d , A d , A d , A d ) √√ GL_ONE_MINUS_DST_ALPHA (1, 1, 1, 1) − (A d , A d , A d , A d ) √√ GL_SRC_ALPHA_SATURATE (f, f, f, 1), f = min(A s , 1 − A d ) √ If the color buffer does not include an alpha channel, the destination alpha A d is consid- ered to be 1 in the previous equations. Probably the most common uses for blending are rendering translucent objects and edge antialiasing. You would prepare blending by calling glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); To get the correct blending results, you should first draw the opaque objects, then sort the transparent ones, and render them in a back-to-front order. 220 OPENGL ES RASTERIZATION AND FRAGMENT PROCESSING CHAPTER 9 9.6.2 DITHERING Dithering is a mechanism for reducing the visual artifacts generated by quantization of color values to low bit-depth displays (see Figure 3.24). For example, a 5-bit per channel display shows clearly visible banding in smooth color gradients. Dithering masks this banding by applying noise to the image when converting the fragment RGB components from a higher bit depth to a lower one. This usually improves the quality of the result- ing image. However, when rendering scenes that contain a lot of overlapping transparent surfaces (e.g., particle systems), the dithering process itself may create visible artifacts as the noise patterns are applied multiple times to each pixel. In such situations it may make sense to manually disable the dithering. This is done by using glDisable with the sym- bolic constant GL_DITHER (by default dithering is enabled). Note that dithering is not a required feature for an OpenGL ES implementation. 9.6.3 LOGIC OPS Logical operations are an alternative to blending. When enabled, the operation between the fragment and the corresponding pixel in the frame buffer is a bit-wise logical one rather than arithmetic, and blending is disabled, regardless of whether GL_BLEND is enabled or not. Logic ops are turned on and off using glEnable and glDisable with the symbolic constant GL_COLOR_LOGIC_OP. By default logic ops are disabled. void glLogicOp(GLenum opcode) is used for selecting the logical operation. The following symbols are supported: GL_CLEAR, GL_SET, GL_COPY, GL_COPY_INVERTED, GL_NOOP, GL_INVERT, GL_AND, GL_NAND, GL_OR, GL_NOR, GL_XOR, GL_EQUIV, GL_AND_REVERSE, GL_AND_INVERTED, GL_OR _REVERSE, and GL_OR_INVERTED. Pitfall: Even though the specification requires support of logic ops, there are some hard- ware implementations that do not support them. 9.6.4 MASKING FRAME BUFFER CHANNELS The last stage of the graphics pipeline involves optional masking of some channels of the frame buffer to disallow writes to them. void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) is used for selecting which of the RGBA channels are active. By default, rendering is per- formed for all four channels. Pitfall: Some existing hardware implementations slow down if you mask independent color channels. Disabling and enabling all of the channels is typically fast, however. SECTION 9.6 APPLYING FRAGMENTS TO THE COLOR BUFFER 221 void glStencilMask(GLuint mask) defines a bitmask that is used to disable writing to individual stencil planes. A stencil plane is enabled if the corresponding bit is set to one. By default all the planes are enabled. void glDepthMask(GLboolean flag) controls whether the depth buffer is updated after a successful depth comparison. By default, depth writes are performed, and this is the wanted behavior for most shaders. However, when transparent surfaces are rendered, it often makes sense not to update the depth buffer. Also in multipass algorithms the latter passes often enable depth test but disable depth writing. The mask functions are applied to all operations that affect the corresponding buffer, i.e., rendering calls and glClear. This page intentionally left blank 10 CHAPTER MISCELLANEOUS OPENGL ES FEATURES This chapter covers OpenGL ES functionality that is not part of either the geometry or the rasterization pipelines. Such functionalit y includes state control, whole-screen operations, state queries, hints, and some extensions. 10.1 FRAME BUFFER OPERATIONS Several operations affect the entire frame buffer. A number of API calls are provided for clearing the various buffers, and reading back the contents of the color buffer. 10.1.1 CLEARING THE BUFFERS Typically, the first operation on a new frame is clearing the various buffers to preset values. Often the color buffer is cleared to contain the color of the sky or other background, the depth buffer is initialized to the maximum depth value, and the stencil buffer is set to zero. Although the buffers could also be initialized by rendering a quad that covers the entire screen, using the dedicated glClear call is usually much faster. void glClear(GLbitfield mask) 223 . GL_TRUE ); draw_scene _with_ normal_light(); 218 OPENGL ES RASTERIZATION AND FRAGMENT PROCESSING CHAPTER 9 9.5.4 DEPTH TESTING Depth testing is the final test in the OpenGL ES fragment pipeline 214 OPENGL ES RASTERIZATION AND FRAGMENT PROCESSING CHAPTER 9 9.5 PIXEL TESTS Toward the end of the graphics pipeline the pixels are subjected to a sequence of tests. The first of the tests is. BLENDING Blending takes the incoming fragment color (with texturing and fog already applied) and the color that already exists in the frame buffer, and uses them to come up with a new color to

Ngày đăng: 03/07/2014, 11:20

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan