The depth of the test
In the last five, OpenGL rendering skills: on the back of the elimination, the end of the article also left a problem unresolved, before solving, first say why this phenomenon
Donut gap causes
As can be seen from the figure, when the front and back parts overlap during the rotation of the doughnut, for us, the front part needs to be displayed, while the back part is the hidden surface. However, OpenGL cannot clear the distinction between the two layers, which is shown in the front and which is shown in the back, resulting in the gap in the doughnut.
Before we tackle this problem, let’s look at a few concepts
The depth of the
Depth is the distance between the Z coordinate of a pixel and the observer in the OpenGL coordinate system
The depth has the following relationship with the Z coordinates of pixels in the graph:
- If the observer is in the positive direction of the z-axis, the larger the z-value is, the closer it is to the observer
- If the observer is in the negative direction of the Z-axis, the smaller the z-value, the closer it is to the observer
The following illustration is for personal understanding, if there is any mistake, please comment
In fact, we should be based on two kinds of observation method to understand the relationship between depth and Z coordinates, below is based on the observer, the object of observation, discussing observer in the Z axis of plus or minus axis, the depth value Z coordinate values of the relationship between objects and, based on another way of observation shows that there is not much do can on the basis of the illustration, go to exercise.
Depth Buffer
The depth cache is a dedicated memory area, stored in video memory, used to store the depth value of each pixel of the graph drawn on the screen
- The greater the depth value, the farther away it is from the observer
- The smaller the depth value, the closer the inner observer
This can also be seen in the diagram above of the relationship between the depth value and the z-value, which will not be explained here.
Deep cache principle
You map the depth value to each pixel on the screen, and then store the depth value in the depth buffer.
- In the depth cache, only one depth value is recorded for each pixel
- The depth buffer ranges from 0 to 1. The default value is 1.0, indicating the maximum depth value
In the previous demo, the zaiRenderScene function was used to empty the buffer before rendering. This includes the depth buffer, because if the buffer is not empty, the previous data will remain, which will affect the rendering of the current image.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Copy the code
The depth of the test
When an object in the paint, pixels in depth and new depth values need to cache the depth of the existing value, if the new value > the old value, it discards this part does not draw, on the contrary, update the depth buffer, a new depth value due to the depth buffer zone is one-to-one with the color buffer, we also need to update the pixel color values to the buffer, This process is called depth testing
In view of the donut gap problem, we need to use depth test to solve, need to open the depth test glEnable(GL_DEPTH_TEST) before donut drawing; Is used to compare old and new depth values to determine whether pixel points should be drawn or discarded. Therefore, based on the previous code, the RenderScene function needs to be modified, as shown in the following flowchart
- The logic of opening and closing depends mainly on the number of clicks on the right menu, opening the first time, closing the second time, and so on
if(iDepth){
glEnable(GL_DEPTH_TEST);
}else{
glDisable(GL_DEPTH_TEST);
}
Copy the code
- Deep testing needs to be turned off after drawing
glDisable(GL_DEPTH_TEST);
Application scenarios of in-depth testing
- Similar to the donut gap problem, OpenGL can’t tell when two parts of an object overlap while rotating, causing the gap to appear.
- Use depth testing to address hidden surface elimination,
Summary of hidden surface elimination scheme
- Front and back elimination: You need to determine the visible part and the hidden side of the user according to the sequence of vertex data. The hidden side is discarded directly, and only the visible part is drawn
- Depth test: you can solve the hidden surface elimination problem at one time. The principle is that no matter how many layers there are, only show the visible layer, the rest of the invisible are discarded
Polygon migration
Z-fighting (Z conflict, flicker) problem
After the depth test is enabled, OpenGL cannot judge the depth value when the error is small due to the limited accuracy of the depth buffer, resulting in the phenomenon of staggered flash of pictures, as shown in the following figure
The main reason for the problem is that the graphics are too close to each other, which makes it impossible to distinguish the layer order. To solve this problem, OpenGL provides a solution of Polygon Offset
To use polygon offset, there are three main steps
- Before drawing, turn on polygon offset
glEnable(GL_POLYGON_OFFSET_FILL)
Copy the code
Enumeration value of polygon offset | Corresponding image fill mode |
---|---|
GL_POLYGON_OFFSET_POINT | GL_POINT |
GL_POLYGON_OFFSET_LINE | GL_LINE |
GL_POLYGON_OFFSET_FILL | GL_FILL |
- Specify offset
glPolygonOffset (GLfloat factor, GLfloat units);
, the parameter is usually -1 and -1 - After drawing, turn off polygon offset
glDisable(GL_POLYGON_OFFSET_FILL)
Copy the code
Prevent ZFighting flicker
- Avoid two objects being too close together: when drawing, insert a small offset
- Close to the clipping surface (set when setting perspective projection) set farther away from the observer: improves accuracy within the clipping area
- Use higher bit depth buffers: Improves depth buffer accuracy
hybrid
After the depth test is enabled, if one of the two overlapping layers is translucent and the other is non-translucent, the color value cannot be covered by comparing the depth value. Instead, the two colors need to be mixed and stored in the color buffer.
There are two ways to mix colors according to different needs
-
Switch mode
It is used to simply mix colors when two layers are overlapped. This blending does not solve the color blending. This can be used in both fixed shaders and programmable shaders
// Enable glEnable(GL_BlEND); / / close glDisable (GL_BlEND);Copy the code
-
Switching mode + mixed equation
To deal with similar filter effect of the scene, a brief description of the image is to need to deal with colors and images on the cover of translucent color The two colors together, as if simply switch mode, have already can’t meet our requirements, need to be mixed with formula, to achieve a mixture of two colors. Commonly used in programmable shaders in chip shaders.
// Enable glEnable(GL_BlEND); // Set the blending factor -- the default is GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); / / close glDisable (GL_BlEND);Copy the code
In the glBlendFunc method, the color combination is obtained by mixing the equation, as shown below by default
Cf = (CS * S) + (Cd * D) = (CS * S) + (Cd * D)Copy the code
==> In the mixing equation, the higher the alpha value of the new color, the higher the new color component will be added, and the less the old color value will be retained
conclusion
- In the color buffer, only one color can be stored per pixel
- Color blending is mainly used to achieve the effect of drawing transparent objects in front of opaque ones
- Color blending should be turned on only if the top layer is transparent. If not, there is no need to turn color Blending on
Case 04: Color mixing
Is in the square key control Demo on the basis of some changes, when the square moved to overlap with the fixed square, their overlapping parts will occur color mixing to form a new color value, stored in the color buffer. The final effect looks like this:
[image upload failed…(image-1f08FD-1604809703077)]
The main flow chart is as follows
-
Four fixed squares were created in SetupRC and the moveable squares were set to translucent
-
RenderScene function turns color blending on before rendering and turns color blending off after rendering. The main flow of the function is as follows
As can be seen from the flow chart, the core code of the color combination is described as follows
- through
glEnable
Open the combination - through
glBlendFunc
, turn on the composition function, calculate the blending factor, and update all pixels on the screen every time you render - Draws a removable square
- After drawing, you need to turn off the blending function and pass through
glDisable
Closed because if not closed, it will have an impact on other projects. Mixed open is for the whole project, not just the project
//1. Enable glEnable(GL_BLEND); //2. Enable the composition function to calculate the blending factor -- every rendering will update all the pixels on the screen // Blending equation: Cf = (Cs * S) + (Cd * D) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //* Use unit shader // Parameter 1: Simply use the default Cartesian coordinate system (-1, 1) and apply one color to all fragments. GLT_SHADER_IDENTITY parameter 2: / / shader color shaderManager. UseStockShader (GLT_SHADER_IDENTITY vRed); //4. The container class starts drawing squareBatch.draw (); //5. Disable glDisable(GL_BLEND);Copy the code