-
The donut case
-
Case analysis
This project on a blog and the drawing of the pyramids, the case of hexagonal drawing process is basically the same, is on a blog created several patterns can monitor the blank space key to switch, according to the design of each of the case without the blank space key surveillance, and how it is change, on a blog is through matrix to transform graphic transformation model, This column transforms the graph by changing the observer matrix. If you have any questions about the drawing process, you can see the blogJuejin. Cn/post / 685041…
-
The results
-
-
Causes of problems and solutions
On the run results will find can appear obviously in the process of turning black area, the reason is very simple, first of all to define according to the light source is the sun must be the color of the display is normal, no light source according to the place which is just how it must be black, and in the process of graphic rotation OpenGl don’t know what to show light or shadow, So that’s where the red and black alternates. Solution:
- Oil painter algorithm
Draw from far and near to cover the overlapping parts, but this also has the problem of highlighting the phenomenon of overlapping figures such as:
- Turn on the front and back to eliminate invisible faces without drawing.
First is eliminating performance can save 50% on the back, for example, a cube, can only see a single surface, out on the back of positive just draw three faces three other invisible surface don’t have to draw a also is the default in OpenGL counterclockwise draw triangle is positive, of course, you can change to clockwise as positive, However, this is generally not recommended, mainly because this setting applies not only to your project, but to OpenGL globally.
Front and back elimination correlation method- glEnable(GL_CULL_FACE); Enable front and back culling (default back culling)
- glDisable(GL_CULL_FACE); Close front and back
- glFrontFace(GLenum mode); Modify the positive functions GL_CW (clockwise),GL_CCW (counterclockwise), default GL_CCW
- glCullFace(GLenum mode); Set GL_FRONT front, GL_BACK back, and GL_FRONT_AND_BACK to exclude front and back faces
- Oil painter algorithm
-
The depth of the test
After the above problems are added on the back, there will be a little problem, and then rotate to see the effect
The problem is that there’s a gap in the doughnut, and what’s the reason for that gap and what’s the solution?
- why Because opened the back, so will leave side but does not render the other, but when the donuts rotation to the vertical direction is the overlap of the two surfaces (positive/negative) at the same time, openGL just don’t know the surface change display that face to the front to the back, there led to the gap problem
- Solution (Enable depth testing)
- Concepts related to depth testing
- What depth is actually the z-value, the distance from the object to the camera and the observer can be placed anywhere in the coordinate system, so. It is not simple to say that the larger or smaller Z is, the closer the observer is to the object;
- Depth buffer Depth buffer is stored in video memory, which is to store depth. It is to associate and store the depth value of the distance from the observer plane (near clipping plane) with each pixel point in the window 1 to 1. GLFW automatically generates such a buffer for you (just as it also has a color buffer to store the colors of the output image). The depth value is stored in each fragment (as the z-value of the fragment). When the fragment wants to output its color, OpenGL will compare its depth value to the Z-buffer. If the current fragment is behind another fragment, it will be discarded, otherwise it will be overwritten. This process is called Depth Testing, and it is done automatically by OpenGL. The default value of the depth buffer is 1.0. This indicates the maximum depth value. Depth values range from [0,1].
- The main function of depth testing is to determine which side should be discarded and which side should be left through z value judgment
- Enable or disable the depth test and explain related parameters
- Clear depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- Enable depth testing
glEnable(GL_DEPTH_TEST);
- Turn off depth testing
glDisable(GL _ DEPTH _ TEST);
- Test rules of the depth test Modify the glDepthFunc(GLenum func) function to modify related parameter descriptions
parameter instructions GL_ALWAYS Always pass the test GL_NEVER Always fail the test GL_LESS Passes when the current depth value < the stored depth value GL_EQUAL Passes when the current depth value = the stored depth value GL_LEQUAL Passes when the current depth value <= is the stored depth value GL_GREATER Passes if the current depth value > the stored depth value GL_NOTEQUAL Passes if the current depth value is not equal to the stored depth value GL_GEQUAL Passes if the current depth value >= the stored depth value
- Clear depth buffer
- Z-fighting: The potential risks of deep testing. Flicker) question
Now, the new question is what happens when you have a flicker in some places, what’s the reason for that
-
Multiple layers appear in the same position, but each layer is very close to each other (the distance between layers indicates the maximum accuracy of the depth buffer), so openGL cannot distinguish between layers, causing the flicker problem
-
The solution
- Enable polygon offset: Allow spacing between depth values. If there is a space between two shapes, does that mean there will be no interference? This can be interpreted as slightly increasing the depth value of the cube before performing the depth test. Thus, the depth values of two overlapping graphs can be distinguished.
GlEnable (GL_POLYGON_OFFSET_FILL) parameter list: GL_POLYGON_OFFSET_POINT GL_POINT GL_POLYGON_OFFSET_LINE Mode: GL_LINE GL_POLYGON_OFFSET_FILL Mode: GL_FILLCopy the code
- Specify offset
- GlPolygonOffset, which takes 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.
- An Offset greater than zero will push the model farther away from you, and a corresponding Offset less than zero will pull the model closer
- In general, simply assigning -1 and -1 to glPolygonOffset is enough.
Finally remember to turn off polygon offset glDisable(GL_POLYGON_OFFSET_FILL)
-
- How to prevent ZFighting flicker problem
- Do not place two objects too close together to avoid overlapping triangles when rendering. This approach requires the insertion of a small offset for the objects in the scene, so it is possible to avoid ZFighting. For example, in the cube and plane problem above, the problem can be solved by moving the plane down 0.001f. Of course there is a cost to manually inserting this small offset.
- Set the clipping surface as close to the viewer as possible. As we saw above, the depth accuracy is very high near the near clipping plane, so keeping the near clipping plane as far away as possible increases the accuracy of the entire clipping range. However, in this way, objects close to the observer will be clipped, so it is necessary to adjust the clipping surface parameters.
- The use of higher – bit depth buffers, typically 24 – bit depth buffers, is now used on some hardware using 32/64 – bit buffering to improve accuracy
- Concepts related to depth testing
-
The complete code
#include "GLTools.h" #include "GLMatrixStack.h" #include "GLFrame.h" #include "GLFrustum.h" #include "GLGeometryTransform.h" #include <math.h> #ifdef __APPLE__ #include <glut/glut.h> #else #define FREEGLUT_STATIC #include <GL/glut.h> #endif//// Set the role frame as camera GLFrame viewFrame; // Use GLFrustum class to set perspective projection GLFrustum viewFrustum; GLTriangleBatch torusBatch; GLMatrixStack modelViewMatix; GLMatrixStack projectionMatrix; GLGeometryTransform transformPipeline; GLShaderManager shaderManager; // mark: back cull, depth test int iCull = 0; int iDepth = 0; Void ProcessMenu(int value) {switch(value) {case1: iDepth = ! iDepth;break; case2: iCull = ! iCull;break; case 3: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break; case 4: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break; case 5: glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break; } glutPostRedisplay(); Void RenderScene(void) {void RenderScene(void) {void RenderScene(void) {void RenderScene(void) {void RenderScene(void) {void RenderScene(void) {void RenderScene(void) {void RenderScene(void) {void RenderScene(void) {void RenderScene(void); What problems are caused by rendering. Residual data glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Check whether backculling is enabled by setting the iCull flagif(iCull) { glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glCullFace(GL_BACK); } elseglDisable(GL_CULL_FACE); // Set the iDepth flag to determine whether to enable depth testingif(iDepth) glEnable(GL_DEPTH_TEST); elseglDisable(GL_DEPTH_TEST); / / the camera matrix pressed into the matrix model modelViewMatix. PushMatrix (viewFrame); GLfloatVRed [] = {1.0f, 0.0f, 0.0f, 1.0f}; // Use plane shader // Parameter 1: plane shader // Parameter 2: model view projection matrix // parameter 3: Color / / shaderManager. UseStockShader (GLT_SHADER_FLAT, transformPipeline GetModelViewProjectionMatrix (), vRed); GLT_SHADER_DEFAULT_LIGHT // Parameter 1: GLT_SHADER_DEFAULT_LIGHT // 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); / / Draw torusBatch. The Draw (); . / / the stack modelViewMatix PopMatrix (); glutSwapBuffers(); } voidSetupRC() {// Set the background color glClearColor(0.3f, 0.3f, 0.3f, 1.0f); / / initialize shader manager shaderManager InitializeStockShaders (); // Move the camera backward 7 units: distance between naked eye and object viewframe.moveForward (7.0); // create a doughnut //void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloatminorRadius, GLint numMajor, GLint numMinor); // Parameter 1: GLTriangleBatch Container help class // Parameter 2: outer edge radius // Parameter 3: inner edge radius // Parameter 4, 5: GltMakeTorus (torusBatch, 1.0f, 0.3F, 52, 26); // Point size glPointSize(4.0f); } void SpecialKeys(int key, int x, int y) {if(GLUT_KEY_UP) viewFrame.rotateWorld (m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);if(GLUT_KEY_DOWN) viewFrame.rotateWorld (m3dDegToRad(5.0), 1.0f, 0.0f, 0.0f);if(GLUT_KEY_LEFT) viewFrame.rotateWorld (m3dDegToRad(-5.0), 0.0f, 1.0f, 0.0f);if(GLUT_KEY_RIGHT) viewFrame.rotateWorld (m3dDegToRad(5.0), 0.0f, 1.0f, 0.0f); // Refresh window glutPostRedisplay(); } void ChangeSize(int w, int h) { //1. Prevent h from going to 0if(h == 0) h = 1; //2. Set the size of the viewport window glViewport(0, 0, w, h); / / 3. SetPerspective function parameter is a field of view Angle from peak looked Angle value in () / / set the perspective model, initialize its perspective matrix viewFrustum. SetPerspective (35.0 f,float(w)/float(h), 1.0 f, 100.0 f); / / 4. The perspective against projectionMatrix in the matrix. The matrix loaded into perspective LoadMatrix (viewFrustum. GetProjectionMatrix ()); / / 5. Initialize the rendering pipeline transformPipeline. SetMatrixStacks (modelViewMatix projectionMatrix); } int main(int argc, char* argv[]) { gltSetWorkingDirectory(argv[0]); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); glutInitWindowSize(800, 600); glutCreateWindow("Geometry Test Program"); glutReshapeFunc(ChangeSize); glutSpecialFunc(SpecialKeys); glutDisplayFunc(RenderScene); // Create the Menu glutCreateMenu(ProcessMenu); glutAddMenuEntry("Toggle depth test", 1); glutAddMenuEntry("Toggle cull backface", 2); glutAddMenuEntry("Set Fill Mode", 3); glutAddMenuEntry("Set Line Mode", 4); glutAddMenuEntry("Set Point Mode", 5); glutAttachMenu(GLUT_RIGHT_BUTTON); GLenum err = glewInit(); if(GLEW_OK ! = err) { fprintf(stderr,"GLEW Error: %s\n", glewGetErrorString(err)); return 1; } SetupRC(); glutMainLoop(); return 0; } Copy the code