Template Test
First, the template test requires a template buffer, which is specified during OpenGL initialization. If you use the glut toolkit, you can add the maid in the parameter when calling the gluinitdisplaymode function, for example: gluinitdisplaymode (FIG );
You can enable or disable the template test by using glenable/gldisable.
OpenGL saves a "template value" for each pixel in the template buffer. When the pixel needs to perform a template test, it compares the set template reference value with the "template value" of the pixel, if the test is passed and the condition is not met, it is discarded and not drawn.
The condition settings are similar to those in the Alpha test. However, in the Alpha test, floating point numbers are used for comparison, while in the template test, integers are used for comparison. There are also eight comparison cases: always pass, never pass, pass if greater than, pass if smaller than, pass if greater than or equal to, pass if less than or equal to, pass if equal to, pass if not equal.
This Code sets the template test condition as: "if it is less than 3, it passes ". The first two parameters of glstencilfunc are similar to those of glalphafunc. The third parameter indicates that, if compared, only the binary value of mask is 1. For example, if the template value of a certain pixel is 5 (Binary 101), and the binary value of mask is 00000011, because only the last two digits are compared, and the last two digits of 5 are 01, they are actually less than 3, therefore, the test is passed.
How to Set the "template value" of pixels? The glclear function can reset the template values of all pixels. The Code is as follows:
You can reset the color value and template value at the same time:
Just as you can use the glclearcolor function to specify the color after the screen is cleared, you can also use the glclearstencel function to specify the "template value" after the reset ".
The "template value" of each pixel is changed based on the template test results and the results of the deep test.
This function specifies how the "template value" Changes in three cases. The first parameter indicates how the template test is changed when it is not passed; the second parameter indicates how the template test is passed, but the depth test is not passed; the third parameter indicates how the template test and the deep test change. If the template test is not started, the template test is always passed. If the deep test is not enabled, the deep test is always passed)
The changes can be:
Gl_keep (not changed, which is also the default value ),
Gl_zero (return to zero ),
Gl_replace (use the set value in the test condition to replace the current template value ),
Gl_incr (increases by 1, but remains unchanged if it is already the maximum ),
Gl_incr_wrap (increase by 1, but if it is already the maximum value, it starts from scratch ),
Gl_decr (1 less, but remains unchanged if it is already zero ),
Gl_decr_wrap (reduce 1, but if it is already zero, reset it to the maximum value ),
Gl_invert (bitwise inversion ).
In the new version of OpenGL, The glstencilfuncseparate function and glstencilopseparate function can be used to change the template test conditions and template values on the front and back of a polygon. These two functions are similar to glstencilfunc and glstencilop, respectively. They only have a parameter "face" added at the beginning to specify the plane that is currently set. You can select gl_front, gl_back, and gl_front_and_back.
Note: The template buffer is a little different from the depth buffer. Whether or not deep testing is enabled, the depth value of this pixel is always reset when pixels are drawn (unless gldepthmask (gl_false);) is set );). If the template test is not enabled, the template value of the pixel remains unchanged. The template value of the pixel can be modified only when the template test is enabled. (This conclusion was obtained from my own experiment, and I have not found any information on it. If there are any errors, please correct them)
In addition, although the template test is provided from OpenGL 1.0, there seems to be not many hardware implementation template tests for personal computers, many computer systems directly use CPU operations to complete template testing. Therefore, in some old graphics cards or most integrated graphics cards, a large number of frequent use of template tests may cause low program running efficiency. Do not use the glstencilfuncseparate and glstencilopseparate functions for high-end personal computers.
As mentioned above, you can use the cropping test to limit the area to the area of a rectangle. However, if you want to restrict the area to an irregular area, you need to use a template for testing.
For example, draw a lake and the surrounding trees, and then draw the reflection of the trees in the lake. To ensure that the reflection is properly restricted on the lake surface, you can use a template for testing. The procedure is as follows:
(1) Close the template test and draw the ground and trees.
(2) Enable the template test and use glclear to set the template value of all pixels to 0.
(3) set glstencilfunc (gl_always, 1, 1); glstencilop (gl_keep, gl_keep, gl_replace); To draw the lake surface. In this way, the "template value" of pixels on the lake surface is 1, while the "template value" of pixels in other places is 0.
(4) set glstencilfunc (gl_equal, 1, 1); glstencilop (gl_keep, gl_keep, gl_keep); To draw the reflection. In this way, only the pixels with the "template value" being 1 will be drawn. Therefore, only the pixels of the "water surface" can be replaced by the reflected pixels, while the hidden pixels remain unchanged.
Let's look at a real example. This is a simple scenario: A Sphere and a plane mirror exist in the space. We can see the image of the sphere in the plane mirror at a special observation point, and the image is on the edge of the plane mirror. Some images cannot be displayed due to the size limitation of the plane mirror. The effects of the entire scenario are as follows:
The idea of drawing this scenario is similar to the lake reflection mentioned above.
If the plane where the plane mirror is located is exactly the plane determined by the X axis and Y axis, then the sphere and its image in the plane mirror are about this plane symmetry. We use a draw_sphere function to draw a sphere. First, we call this function to draw the sphere itself, then call glscalef (1.0f, 1.0f,-1.0f), and then call the draw_sphere function, you can draw a sphere image.
Note that the deep test is enabled because it is a 3D scenario. However, in the observer's position, the image of the sphere is actually behind the plane mirror. That is to say, if the image is drawn in the conventional way, the plane mirror will overwrite the image, this is not what we want. Solution: Set the depth buffer to read-only, draw a plane mirror, set the depth buffer to a writable state, and draw the image behind the plane mirror.
Some may ask: if the deep test is disabled when the image is drawn, will the image not be blocked by the plane mirror? Why do I need to enable the deep test and set the deep buffer to read-only? The actual situation is: Although disabling the deep test does prevent the image from being blocked by the plane mirror, the image itself may have several problems. The image we see is a sphere, but in fact this sphere is composed of many polygon. Some of these polygon represent what we can see as "Front ", some represent the "back" we cannot see ". If the deep test is disabled, and some "back" polygon are drawn first than the "front" polygon, the back of the sphere will block the front, which is not the expected effect. To ensure that the front side can block the back, you should enable the deep test.
The code for plotting is as follows:
// Draw a sphere
Glcolor3f (1, 0, 0 );
Glpushmatrix ();
Gltranslatef (0, 0, 2 );
Glusolidsphere (0.5, 20, 20 );
Glpopmatrix ();
}
Void display (void)
{
// Clear the screen
Glclear (gl_color_buffer_bit | gl_depth_buffer_bit );
// Set the observation point
Glmatrixmode (gl_projection );
Glloadidentity ();
Gluperspective (60, 1, 5, 25 );
Glmatrixmode (gl_modelview );
Glloadidentity ();
Glulookat (5, 0, 6.5, 0, 0, 0, 0, 1, 0 );
Glenable (gl_depth_test );
// Draw a sphere
Gldisable (gl_stencil_test );
Draw_sphere ();
// Draw a plane mirror. Set template buffer while drawing.
// In addition, to ensure that the image after the plane mirror can be correctly drawn, you must set the depth buffer to read-only when drawing the plane mirror.
// Temporarily disable the illumination effect during painting
Glclearstenpencil (0 );
Glclear (gl_stencil_buffer_bit );
Glstencilfunc (gl_always, 1, 0xff );
Glstencilop (gl_keep, gl_keep, gl_replace );
Glenable (gl_stencil_test );
Gldisable (gl_lighting );
Glcolor3f (0.5f, 0.5f, 0.5f );
Gldepthmask (gl_false );
Glrectf (-1.5f,-1.5f, 1.5f, 1.5f );
Gldepthmask (gl_true );
// Draw a sphere that is symmetric with the previous sphere about the plane mirror. Note that the position of the light source must also be changed.
// Because the plane mirror is a plane determined by the X axis and Y axis, symmetry can be achieved as long as the zcoordinate is reversed.
// In order to ensure that the sphere is restricted within the plane mirror, use the template for testing.
Glstencilfunc (gl_equal, 1, 0xff );
Glstencilop (gl_keep, gl_keep, gl_replace );
Glscalef (1.0f, 1.0f,-1.0f );
Draw_sphere ();
// Exchange Buffer
Gluswapbuffers ();
//
Grab ();
}
You may feel that the settings for template testing are so complicated that many functions can be implemented. There must be more than one "limit the pixel painting range ". This is actually the case, but now we only want to talk about this.
In fact, if you do not need to draw a translucent effect, sometimes you can use the hybrid function to replace the template test. The following steps can be used to draw an image:
(1) Clear the screen, set the appropriate value in glclearcolor to ensure that the alpha value of the pixel after the screen is cleared is 0.0
(2) disable the blending function, draw the sphere itself, and set the appropriate color (or illumination and material) to ensure that the alpha value of all drawn pixels is 0.0
(3) Draw a plane mirror and set the appropriate color (or illumination and material) to ensure that the alpha value of all painted pixels is 1.0
(4) Enable the hybrid function. Use gl_dst_alpha as the source factor, and gl_one_minus_dst_alpha as the target factor. In this way, only pixels with the original alpha of 1.0 can be modified, the pixels with Alpha 0.0 remain unchanged. Then, draw the image object. Make sure that the alpha value of all painted pixels is 1.0.
In some OpenGL implementations, template testing is implemented by software, while hybrid functions are implemented by hardware. In this case, you can consider this alternative method to improve the running efficiency. However, not all template tests can be replaced by the hybrid function. Such replace is not natural, complex, and error-prone.
In addition, always note: when using a mixture for simulation, even if the original Alpha value of a pixel is 0.0, the color of a pixel does not change after painting, however, the depth value of this pixel may be modified. If a template test is used, the depth value of the pixel that fails the test will not change. In addition, in the template test and hybrid functions, the pixel template value modification methods are different.
In Windows, even if the template buffer is not explicitly required, the template buffer is sometimes allocated. However, to ensure the versatility of the program, it is best to specify the template buffer. If no template buffer is allocated, all pixels for template testing will pass the test.
At the end of the display function, a grab function is called to save the current image to a BMP file. This function was originally used in both Lesson 10 and lesson 11th. However, I found a bug, but now I have modified it: Add glreadbuffer (gl_front); to the beginning of the function. Note that this function should be called immediately after it is drawn (if dual buffering is used, it should be called after the switching buffer.
Template testing is a complex method in all OpenGL tests. Glstencilfunc (gl_less, 3, mask );Glclear (gl_stencil_buffer_bit );Glclear (gl_color_buffer_bit | gl_stencil_buffer_bit );Glstencilop (fail, zfail, zpass );Void draw_sphere (){// Set the light sourceGlable (gl_lighting );Glable (gl_light0 );{GlfloatPos [] = {5.0f, 5.0f, 0.0f, 1.0f },Ambient [] = {0.0f, 0.0f, 1.0f, 1.0f };Gllightfv (gl_light0, gl_position, POS );Gllightfv (gl_light0, gl_ambient, ambient );}