preface

This article is an introduction to some of the most important concepts in OpenGL. The purpose is to understand the following three lines of code.

// Enable depth testing
glEnable(GL_DEPTH_TEST);
// Turn on positive culling
glEnable(GL_CULL_FACE);
// Enable polygon offset
glEnable(GL_POLYGON_OFFSET_FILL);
Copy the code

What is hidden face elimination?

Hidden face elimination: When drawing a 3D scene, we need to decide which parts are visible to the observer and which parts are not and should be discarded early.

For example: objects behind an opaque wall should not be rendered. This condition is called hidden face elimination.

The figure above is a circle drawn with OpenGL in the previous Demo. Everything looks normal from the front, but when we use the arrow keys to move the perspective, the problem will appear as shown in the picture below

How to solve hidden face elimination?

1. The painting method

What is oil painting?
  • Draw objects in the scene that are farther away from the observer, and then draw objects that are closer.
  • As shown in the figure below: First draw the red part (far), then draw the yellow part (near), and finally draw the gray part (nearest) to solve the problem of hidden surface elimination.
Why not use oil painting now?
  • We can obviously see it, but the naked eye can’t see it, and the parts that don’t need to be rendered are also drawn first, so this method is very inefficient in graphics processing, so it will not be used in the development of this way.

  • In oil painting, when several objects are at the same distance from the observer, they overlap and cannot be drawn, as shown below

2. Remove the front and back

Why use front and back culling?
  • When we observe a 3D graph from any Angle, we can only see 3 faces at most. The other faces are invisible, so why bother with performance painting if you can’t? This is the heads and tails elimination.

  • OpenGL can do this by examining all faces facing the observer and rendering them. Discard the faces facing back. This saves the performance of the slice shader and improves rendering performance by 50%.

How to use front and back culling?
  • Analyze vertex order, specify front and back, turn on front and back cull.

  • Front and back: The triangles connected by counterclockwise vertices are front triangles and those connected by clockwise vertices are back triangles.

  • Code implementation

// Enable positive culling glEnable(GL_CULL_FACE); // Turn off positive culling glDisable(GL_CULL_FACE);Copy the code
Turn on the effect of front and back culling

Remember the circle that was drawn up there? After the front and back culling is enabled, the effect is shown in the picture below. It can be seen that the three-dimensional sense of the front and back is out, which solves the problem of hidden faces. However, when observing the side of the ring, there is an obvious groove effect. Why is that?

3. Z-buffer square method (Depth buffer)

Why do we need a deep buffer?

The reason for the notch effect is that when drawing the side, the part close to the observer is first drawn, and then the part far from the observer is drawn. The new part will overwrite the previously drawn part, because there is no way to determine who is near and who is far away, which causes this drawing problem.

So what is a depth buffer?
  • First of all, we need to know what depth is, and depth is basically the distance of the pixel from the point of view in the 3D world, the Z value in the XYZ coordinate system, right
  • So what is the depth buffer? It’s just an area of memory that stores the Z value of the pixel. The larger Z is, the further away it is from the observer.
So how do you use the depth buffer?

First of all, what is depth testing?

Each pixel has only one depth value. When a new depth value appears at the same pixel, it will be compared with the previous one. If the new depth value is large, it will be farther away from us and should be blocked. If the new depth value is smaller and closer to us, we should see it first, when the depth buffer stores the smaller depth value and the color buffer is updated accordingly. The whole process of comparing depth values is called depth testing.

To use the depth buffer, you need to turn on the depth test with the following code

glEnable(GL_DEPTH_TEST);

Disable the depth test glDisable(GL_DEPTH_TEST);

Use the depth buffer to enable the effect of depth testing

After the depth test is opened, as shown in the picture below, the grooves on the side are gone. Because of the depth value, it will not draw the part that is blocked, which improves efficiency and solves the problem.

Expansion: Will there be no problems with depth testing?

In fact, this is not the case. As shown in the figure below, when the difference between the depth values of the three figures is very small, the depth test cannot judge the depth value, which will lead to unpredictable problems. This problem is called ZFighting flicker problem

So how to solve the ZFighting flicker problem?

  • Enable Polygon Offset to slightly increase the depth value before performing the depth test so that there is a slight difference between two overlapping shapes

// Enable polygon offset glEnable(GL_POLYGON_OFFSET_FILL);

// Turn off polygon offset glDisable(GL_POLYGON_OFFSET_FILL);

  • If you specify an offset, a negative value will make the z value closer to us, and a positive value will make the Z value further away.
GlPolygonOffset (-1,-1); glPolygonOffset(-1,-1); glPolygonOffset(-1,-1);Copy the code

So how to prevent ZFighting flicker problem?

  1. Do not place two objects too close together and manually avoid overlapping triangles when rendering
  2. Set as close to the clipping surface as possible away from the point of view, because a greater distance will result in higher accuracy throughout the clipping range.
  3. Using a deeper cache of higher bits, typically 24 bits, or 32 bits on some hardware, improves accuracy.

conclusion

  1. The above mentioned three solutions to the elimination of hidden surface, but oil painting can be abandoned, to understand. We usually use a combination of front and back culling and deep testing to solve problems and improve performance.

  2. In OpenGL, there are only a few lines of code for backside culling and deep testing, but you need to understand how it works to have a deep understanding of the entire render.

  3. Since OpenGL is a state machine, it is important to turn it off when not in use after you have enabled front-back culling or depth testing.

Click to see the full demo of this article

OpenGL introduction (a) — OpenGL professional noun analysis

Introduction to OpenGL (2) — Build an OpenGL Mac environment

OpenGL Start (3) — Quickly draw a square

OpenGL introduction (4) – rendering process analysis

OpenGL introduction (five) – metagraph drawing actual combat

OpenGL Introduction (six) – Matrix basic change actual combat

OpenGL introduction (seven) – hidden surface elimination details

OpenGL Start (eight) – Texture coordinate parsing