draw
Let’s draw a doughnut this time. The overall drawing process is the same as that of the previous article. Because OpenGL already provides the torusBatch class for donuts, we don’t have to worry about saying how many vertices it takes to draw a donut. In the previous article, we set the pixel drawing as the observer is still and the pixel is moving. This time, we change the strategy to use the observer is still and the pixel is still and add a default light source.
SetupRC
- Also initialize the background color, shader first
- Move the observer MoveForward to the appropriate position
- Creating a doughnut
//void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloatminorRadius, GLint numMajor, GLint numMinor); GltMakeTorus (torusBatch, 1.0, 0.4, 52, 26); gltMakeTorus(torusBatch, 1.0, 0.4, 52, 26); gltMakeTorus(torusBatch, 1.0, 0.4, 52, 26);Copy the code
GltMakeTorus method, will Begin GLBatch CopyVertexData3f, END method combined together.
-
The size of the initialization point is visible to the naked eye when the convenient point is filled
-
Set up transform pipe
/ / transformation pipeline transformPipeline. SetMatrixStacks (modelViewMatix projectionMatrix);Copy the code
ChangeSize
- Set the viewport
- Set the perspective projection and load it into the Perspective projection matrix stack
- The model view matrix stack records a cell matrix
RenderScene
- Clears the color buffer and depth buffer to set the color of the drawing
- Push the observer matrix onto the model view matrix stack
- Use the default light shader for the stereo effect
// Parameter 1: GLT_SHADER_DEFAULT_LIGHT Default light shader // Parameter 2: model view matrix // Parameter 3: projection matrix // parameter 4: Basic color value shaderManager. UseStockShader (GLT_SHADER_DEFAULT_LIGHT, transformPipeline GetModelViewMatrix (), transformPipeline.GetProjectionMatrix(), vRed);Copy the code
The auxiliary functions are just SpecialKeys
And we’re done. Let’s see what happens.
To explore the reasons for
By default,OpenGL renders all points, lines, and triangles rasterized on the screen and arranged in the order specified when grouping the pixel batches, which can cause problems in some cases. For example, in the image above, the doughnut has drawn a triangle with part of it on the back, which should have been thrown away but wasn’t, and OpenGL doesn’t know how to display the triangle on the front and the triangle on the back as we rotate it. So we need to tell it what to show and what to hide and throw away, and then we can deliver OpenGL rendering performance, because it takes half the work. This method is called hidden face elimination.
Black because of the light shader, the back is dark – black
Oil painting method
But oil painting method is very inefficient in computer graphics processing, and also has great problems
- Any overlap of geometric shapes must be written twice per pixel, and writing in storage slows things down
- Sorting individual triangles is too expensive
- When drawing overlapping images, no clear sequence, can not distinguish the distance of the graph, it can not be processed
Front and back culling
We can define a front and a back for a plane, and OpenGL can do this by checking all the faces that are facing the observer and rendering them, and discarding the faces that are facing back, and OpenGL’s rendering performance increases by 50%.
So how do you tell OpenGL which face is heads? Which is the tails?
The answer is by analyzing the order of the vertex data.
- Face: Triangular faces joined in counterclockwise order of vertices
- Back: Triangular faces joined in clockwise order of vertices
The front and back of the cube are also affected by the position of the observer
- When the observer is on the right, the right triangle is counterclockwise
- When the observer is on the left, the left triangle is counterclockwise
Heads and tails are determined by the order in which the vertices of the triangle are defined and the direction in which the observer is located
// Enable surface culling (default backside culling) glEnable(GL_CULL_FACE); // Turn off surface culling (default backside culling) glDisable(GL_CULL_FACE); GL_FRONT, GL_BACK, GL_FRONT_AND_BACK, default GL_BACK GL_BACK glCullFace(GLenum mode); GL_CCW glFrontFace(GL enum mode); GL_CCW glFrontFace(GL enum mode); GL_CCW glFrontFace(GL enum mode); GL_CCW glFrontFace(GL enum mode);Copy the code
So we need to solve this problem by enabling backside culling in the RenderScene method with glEnable.
At the same time, new problems have arisen.
The depth of the test
Let’s start with a little bit of depth
- Depth is essentially the z value of the distance from the observer in the 3D world. When the observer is on the z axis
Positive direction
, the larger the z value is, the closer it is to the observer, when the observer is in the z axisThe negative direction
, the smaller the z value, the closer it is to the observer - The depth buffer is an area of video memory dedicated to storing the depth value of each pixel (drawn on the screen)
- Without using the depth of the test, if we will draw an object distance closer, longer distance map objects, far away fighting the graphics will be covered with graphics, when using the depth test, the order of the drawing object is not so important, as long as through open the depth buffer, and allow the depth value of writing, OpenGL writes the depth value of the pixel to the buffer for rendering. Unless glDepthMask(GL_FALSE) is called to disable writing
The DepthBuffer (DepthBuffer) corresponds to the ColorBuffer (ColorBuffer). The color cache stores pixel color information, while the depth buffer stores pixel depth information. When deciding whether to draw an object surface, the depth value of the pixel corresponding to the surface is first compared to the value in the current depth buffer. If it is greater than the value in the depth buffer, it is discarded. Otherwise, use the depth value and color value corresponding to this pixel. Update the depth buffer and color buffer separately. This process is called depth testing.
Depth in open test, before drawing each pixel, the depth of the OpenGL will it value and the current pixel corresponding depth values stored in the buffer, and comparison, if the corresponding depth, distance from the observer, will update depth buffer in depth value, also want to update the corresponding color in the color buffer values, otherwise it will be discarded.
The default value of the depth buffer is 1.0, which indicates the maximum depth value. The depth value ranges from 0 to 1.
GlDepthFunc (GLenum func) ¶
// Enable the depth test glEnable(GL_DEPTH_TEST); // Disable the depth test GL_DEPTH_TEST;Copy the code
The effect after being turned on
Z-fighting (Z conflict, flicker)
Open deep testing, still potentially risky. The reason is that the accuracy of depth buffer has its limit. When the depth difference between two layers is very small, OpenGL cannot correctly judge the depth value of the two layers due to the accuracy problem, and the result of depth test becomes unpredictable, unable to determine who is in front and who is behind. There are ambiguations in the display, and the image flickers interlaced.
The solution
Current devices generally do not have the problem of Z-fighting
1. Enable Polygon Offset
Turn on polygon offset to create a gap between depth values. This will determine who is in front and who is behind in depth testing.
// Enable glEnable(GL_POLYGON_OFFSET_FILL) // Disable GL_POLYGON_OFFSET_FILL)Copy the code
parameter | Corresponding mode |
---|---|
GL_POLYGON_OFFSET_FILL | GL_FILL |
GL_POLYGON_OFFSET_LINE | GL_LINE |
GL_POLYGON_OFFSET_POINT | GL_POINT |
2. Specify the offset
- Use glPolygonOffset to specify two parameters: factor, units
- The depth value of each Fragment increases the Offset shown below: Offset = (m * factor) + (r * units);
M: the maximum slope of the depth of a polygon, understanding that the more parallel a polygon is to the near clipplane, the closer m is to 0. R: the minimum discernable difference in the depth values that can be generated in the window coordinate system. R is a constant specified by the specific OpenGL platform.Copy the code
- An Offset greater than zero pushes the model farther away from you, and a corresponding Offset less than zero pulls the model closer
In general, simply assigning -1 and -1 to glPolygonOffset is enough.
Prevention of Z – fighting
- Do not place two objects too close together to avoid overlapping triangles when rendering. A small number of offsets can be inserted at drawing time, but there is a cost to manually inserting offsets
- As close to the cut surface as possible
(Set when setting perspective projection matrix)
Set the clipping far away from the observer, which can improve the accuracy of the clipping range, but also can cause objects close to the observer to be clipped, so you need to adjust the clipping surface parameters - Hardware devices that use higher bits of depth buffer to improve accuracy, commonly 24 bits,
Recommendation:
- OpenGL depth buffer, clipping and blending
- OpenGL rendering techniques: depth testing, polygon offset, blending