I. Case and related functions

Use OpenGL to draw point, line, line segment, line ring, pyramid, hexagon graph, and use the space bar of the keyboard to complete the graph switch, use the up and down keys to control the rotation of the graph up and down. The effect is as follows:

Two, prepare knowledge

1. Required variables and classes:

GLShaderManager shaderManager; GLMatrixStack modelViewMatrix; GLMatrixStack projectionMatrix; GLFrame cameraFrame; GLFrame objectFrame; // GLFrustum viewFrustum; // Container class (7 different primiples correspond to 7 container objects) GLBatch pointBatch; GLBatch lineBatch; GLBatch lineStripBatch; GLBatch lineLoopBatch; GLBatch triangleBatch; GLBatch triangleStripBatch; GLBatch triangleFanBatch; GLGeometryTransform transformPipeline; GLfloat vGreen[] = {0.0f, 1.0f, 0.0f, 1.0f}; GLfloat vBlack[] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat vBlack[] = {0.0f, 0.0f, 0.0f, 1.0f}; Int nStep = 0;Copy the code

Important nouns:

  • Matrix stack:

The GLMatrixStack change pipeline uses the matrix stack, which is used to store our matrices on the stack. ModelViewMatrix: stack of model view matrices, which operate mainly on this matrix, as described later in the code. ProjectionMatrix: perspective projectionMatrix stack

  • GLFrame:

GLFrame refers to the reference frame, which stores one world coordinate point and two world coordinate direction vectors, namely nine glFloat values, representing the current position point, the forward direction vector, and the upward direction vector.

GLFrame can represent the position and direction of any object in the world coordinate system. Both the camera and the model can be represented using GLFrame. For any object represented by GLFrame, there are two coordinate systems involved: the invariable world coordinate system, and the object coordinate system for itself (i.e. the drawing coordinate system). GLFrame also stores matrices, but only one.

Function:

In addition to the function portals used previously in this case:

  • int main(int argc,char *argv[])The main function
  • void changeSize(int w ,int h): changeSize function
  • void RenderScene(void)RenderScene function
  • void setupRC(void)SetupRC function
  • void SpecialKeys(int key, int x, int y)SpecialKey function.

There are also new functions and some variables: // By the number of Spaces. Toggle different window names

  • void KeyPressFunc(unsigned char key, int x, int y):

Function that is called when a space is clicked to handle the function of adjusting the display after pressing a space.

Iii. Code parsing:

mainFunction:

int main(int argc, char* argv[]) { gltSetWorkingDirectory(argv[0]); glutInit(&argc, argv); / / apply for a color area, depth buffer area, double buffer, stencil buffer area glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); // Set the size of window glutInitWindowSize(800, 600); // Create window name glutCreateWindow("GL_POINTS"); GlutReshapeFunc (ChangeSize); GlutKeyboardFunc (KeyPressFunc); GlutSpecialFunc (SpecialKeys); // Display function glutDisplayFunc(RenderScene); GLenum err = glewInit(); // Check whether the glew library can be initialized to ensure that the project can use the OpenGL framework. if (GLEW_OK ! = err) { fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); return 1; } // draw SetupRC(); //runloop runs the loop glutMainLoop(); return 0; }Copy the code

The main function, as mentioned earlier, is used as an entry point to start the program, and in this case, to prepare the program.

changeSizeFunction:

// The window has been resized or just created. Void ChangeSize(int w, int h) {glViewport(0, 0, w, h); / / create the projection matrix and loading it in the projection matrix stack viewFrustum. SetPerspective (35.0 f, float (w)/float (h), 1.0 f, 500.0 f); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); / / call the top load cell matrix modelViewMatrix. LoadIdentity (); }Copy the code

ChangeSize is mainly responsible for the change process of viewports. In this case, it added creating projectionMatrix and incorporating it into projectionMatrix perspective matrix stack and loading element matrix into modelViewMatrix model view moment stack.

pressFunFunction:

// According to the number of Spaces. Void KeyPressFunc(unsigned char key, int x, int y) {if(key == 32) {nStep++; if(nStep > 6) nStep = 0; } switch(nStep) { case 0: glutSetWindowTitle("GL_POINTS"); break; case 1: glutSetWindowTitle("GL_LINES"); break; case 2: glutSetWindowTitle("GL_LINE_STRIP"); break; case 3: glutSetWindowTitle("GL_LINE_LOOP"); break; case 4: glutSetWindowTitle("GL_TRIANGLES"); break; case 5: glutSetWindowTitle("GL_TRIANGLE_STRIP"); break; case 6: glutSetWindowTitle("GL_TRIANGLE_FAN"); break; } glutPostRedisplay(); }Copy the code

This function mainly records the current step and determines the name of the graph to be displayed according to the current step. When all the graphs are displayed, set step to 0 and start the display again.

specialKeysFunction:

Void SpecialKeys(int key, int x, int y) {if(key == GLUT_KEY_UP) // Rotate around a specified x, y, Z axis. ObjectFrame. RotateWorld (m3dDegToRad (5.0 f), 1.0 f, 0.0 f, 0.0 f); If (GLUT_KEY_DOWN) objectFrame.rotateWorld (m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f); If (GLUT_KEY_LEFT) objectFrame.rotateWorld (m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f); If (key == GLUT_KEY_RIGHT) objectFrame.rotateWorld (m3dDegToRad(5.0f, 0.0f, 1.0f, 0.0f); glutPostRedisplay(); }Copy the code

SpecialKeys determines how the current display should rotate based on the button position. Here are the two kinds of rotation we use:

  • Fix the observer and rotate the model. This is used in the code above:
objectFrame.RotateWorld()
Copy the code
  • Fixed the model and rotated the observer. That is:
cameraFrame.RotateWorld()
Copy the code

Void RotateWorld(float fAngle, float x, float y, float z) float x, float y, float z Relative to the X, Y, and Z axes if we want to go around the Y axis, Y = 1, X = Z = 0; Conversely, around the X-axis: let X = 1, Y = Z = 0; Conversely, around the z-axis: let Z = 1 and X = Y = 0.

setupRCFunction:

// This function does any necessary initialization in the rendering context. // This is the first time to do any OpengL related tasks. Void SetupRC() {// Grey background glClearColor(1.0f, 0.7f, 0.7f, 1.0f); shaderManager.InitializeStockShaders(); glEnable(GL_DEPTH_TEST); / / set the transformation pipeline to use the two matrices stack transformPipeline. SetMatrixStacks (modelViewMatrix projectionMatrix); // The default orientation in GLFrame is the negative z-axis, i.e. (0.0, 0.0, -1.0) // Go forward -15.0, That is (0.0, 0.0, 1.0 * 15.0) = (0.0, 0.0, 15.0) cameraFrame. MoveForward (15.0 f); // Define some points, triangular shapes. GLfloat vCoast[9] = {3,3,0,0,3, 3,0,0}; Pointbatch. Begin(GL_POINTS, 3); pointBatch.CopyVertexData3f(vCoast); pointBatch.End(); Linebatch. Begin(GL_LINES, 3); lineBatch.CopyVertexData3f(vCoast); lineBatch.End(); Linestripbatch.begin (GL_LINE_STRIP, 3); linestripbatch.begin (GL_LINE_STRIP, 3); lineStripBatch.CopyVertexData3f(vCoast); lineStripBatch.End(); Lineloopbatch.begin (GL_LINE_LOOP, 3); lineLoopBatch.CopyVertexData3f(vCoast); lineLoopBatch.End(); / / created through triangular pyramid GLfloat vPyramid [12] [3] = {2.0 f, f, 0.0-2.0 f, f 2.0, 0.0 f to 2.0 f, f, 0.0 4.0 f, f 0.0, 2.0 f, 0.0 f to 2.0 f, 0.0 2.0 0.0 2.0 f, f, f, f, f 4.0, 0.0, f 2.0 f, f 0.0, 2.0 f to 2.0 f, 0.0 f, f 2.0, 0.0 f, f 4.0, 0.0 f to 2.0 f, f 0.0, 2.0 f to 2.0 f, 0.0f, -2.0f, 0.0f, 4.0f, 0.0f}; // Triangles define a new triangle, triangleBatch.begin (GL_TRIANGLES, 12), for every three vertices; triangleBatch.CopyVertexData3f(vPyramid); triangleBatch.End(); // Triangle sector -- hexagon GLfloat vPoints[100][3]; int nVerts = 0; // Radius GLfloat r = 3.0f; // origin (x,y,z) = (0,0,0); VPoints [nVerts] [0] = 0.0 f; VPoints [nVerts] [1] = 0.0 f; VPoints [nVerts] [2] = 0.0 f; //M3D_2PI means 2Pi, just like a circle. Draw circles for(GLfloat Angle = 0; angle < M3D_2PI; Angle += M3D_2PI / 6.0f) {// array subscript increment (every increment indicates a vertex) nVerts++; /* // set the value of the x coordinate (Angle) * radius vPoints[npoints][0] = // set the value of the x coordinate (Angle) * vPoints[npoints][0] = float(cos(angle)) * r; // verts sin(Angle) * radius vPoints[npoints][1] = float(sin(Angle)) * r; // vPoints[nVerts][2] = -0.5f; } // Add a closed endpoint to the end of the sector. Add a demo: mask 177-180 lines of code and change the drawing node to 7. The triangle fan cannot be closed. nVerts++; vPoints[nVerts][0] = r; vPoints[nVerts][1] = 0; VPoints [nVerts] [2] = 0.0 f; / / load! Begin(GL_TRIANGLE_FAN, 8); //GL_TRIANGLE_FAN A group of triangles fan-shaped around the center of a circle that share adjacent vertices. triangleFanBatch.CopyVertexData3f(vPoints); triangleFanBatch.End(); // Vertex subscript int iCounter = 0; // radius GLfloat radius = 3.0f; For (GLfloat Angle = 0.0f; Angle < = (2.0 f * M3D_PI); Angle += 0.3f) {// GLfloat X = radius * sin(Angle); GLfloat y = radius * cos(angle); VPoints [iCounter][0] = x; // Draw two triangles (their x and y vertices are the same, but their z points are different). vPoints[iCounter][1] = y; VPoints [iCounter], [2] = 0.5; iCounter++; vPoints[iCounter][0] = x; vPoints[iCounter][1] = y; VPoints [iCounter] [2] = 0.5; iCounter++; } // Close the loop printf(" number of vertices with triangle: %d\n",iCounter); VPoints [iCounter][0] = vPoints[0][0]; vPoints[iCounter][1] = vPoints[0][1]; VPoints [iCounter], [2] = 0.5; iCounter++; vPoints[iCounter][0] = vPoints[1][0]; vPoints[iCounter][1] = vPoints[1][1]; VPoints [iCounter] [2] = 0.5; iCounter++; // GL_TRIANGLE_STRIP A group of triangles that share vertices on a strip. Trianglestripbatch. Begin(GL_TRIANGLE_STRIP, iCounter); triangleStripBatch.CopyVertexData3f(vPoints); triangleStripBatch.End(); }Copy the code

This is mainly responsible for calculating the data needed for our graphics display. GLBatch related functions

Void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0) Parameter 1: using primitive parameters of 2:3: vertices parameters texture coordinates (optional) / / is responsible for the vertex coordinates of copy vertex coordinates void GLBatch: : CopyVertexData3f (GLFloat * vNorms); Void GLBatch::End(void); // Data replication is complete.Copy the code

renderSenceFunction:

/ / call scenario void RenderScene (void) {/ / Clear the window with the current clearing color glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); / / pressure stack modelViewMatrix. PushMatrix (); M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); / / matrix multiply, the top of the stack matrices, the result of the multiplication Jane then stored on the top of the stack modelViewMatrix. MultMatrix (mCamera); M3DMatrix44f mObjectFrame; // Just use the GetMatrix function to get the value at the top of the matrix stack. This function can be overridden twice. Used to use GLShaderManager. Objectframe.getmatrix (mObjectFrame); / / matrix multiply, the top of the stack matrices, the result of the multiplication Jane then stored on the top of the stack modelViewMatrix. MultMatrix (mObjectFrame); /* Uniform values in GLShaderManager -- Plane shader arguments 1: plane shader arguments 2: Operation of geometry transform to specify a 4 * 4 transformation matrix -- transformPipeline. GetModelViewProjectionMatrix () to obtain the GetMatrix function on top of the stack can gain matrix value parameter 3: Color (black). * / shaderManager UseStockShader (GLT_SHADER_FLAT, transformPipeline GetModelViewProjectionMatrix (), vBlack); Switch (nStep) {case 0: // set point size glPointSize(6.0f); pointBatch.Draw(); GlPointSize (1.0 f); break; Case 1: // Set line width glLineWidth(2.0f); lineBatch.Draw(); GlLineWidth (1.0 f); break; Case 2: glLineWidth (2.0 f); lineStripBatch.Draw(); GlLineWidth (1.0 f); break; Case 3: glLineWidth (2.0 f); lineLoopBatch.Draw(); GlLineWidth (1.0 f); break; case 4: DrawWireFramedBatch(&triangleBatch); break; case 5: DrawWireFramedBatch(&triangleStripBatch); break; case 6: DrawWireFramedBatch(&triangleFanBatch); break; } / / restore to the previous model view matrix (matrix) modelViewMatrix. PopMatrix (); GlutSwapBuffers (); }Copy the code

This is mainly dealing with the logic of drawing graphics. PushMatrix () gets the current cameraFrame observer and objectFrame model view matrix and stores it in matrix stack. Then by transformPipeline for MVP matrix (GetModelViewProjectionMatrix ()), and then to the shader, finally PopMatrix () out of the stack. Among them:

  • No matter what kind of graph we draw, we need to reset our point and line widths after drawing. Because as we talked about earlier,OpenGLIs itself a giant state machine.www.jianshu.com/p/29028b406…

). If the current draw is not reset after completion, subsequent draws will be affected. So it needs to be reset after drawing.

// Set line width glLineWidth(2.0f); / / / Draw lineBatch. The Draw (); // set line width glLineWidth(1.0f);Copy the code
  • shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);Use to draw vertices, build the display graphic frame we need;
  • void DrawWireFramedBatch(GLBatch* pBatch)The function is used to draw the fill frame, which we see in green.
Void DrawWireFramedBatch (GLBatch * pBatch) {/ * -- -- -- -- -- -- -- -- -- -- -- -- painted green part -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * / / * GLShaderManager in Uniform value - surface shader Parameter 1: Plane shader parameter 2: run to specify a 4 * 4 transformation matrix for geometric transformation. Color value * / shaderManager. UseStockShader (GLT_SHADER_FLAT, transformPipeline GetModelViewProjectionMatrix (), vGreen); pBatch->Draw(); / * -- -- -- -- -- -- -- -- -- -- - border part -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * / / * glEnable (GLenum mode); Used to enable various functions. Note: the function is determined by the parameters of the parameter list: http://blog.csdn.net/augusdi/article/details/23747081 GlEnable () cannot be written between glBegin() and glEnd() GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_LINE GL_LINE_SMOOTH Zigzag GL_BLEND for filter line points enables color blending. For example, GL_DEPTH_TEST enables the depth test to automatically hide hidden graphics according to the distance of coordinates (material glDisable(GLenum mode); GlPolygonOffset (-1.0f, -1.0f); glPolygonOffset(-1.0f, -1.0f); GlEnable (GL_POLYGON_OFFSET_LINE); GL_POLYGON_OFFSET_LINE; GlEnable (GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Set the front or back of the polygon to wireframe mode by calling glPolygonMode. GlPolygonMode (GL_FRONT_AND_BACK, GL_LINE); // Set line width glLineWidth(2.5f); /* Uniform values in GLShaderManager -- Plane shader arguments 1: plane shader arguments 2: Operation of geometry transform to specify a 4 * 4 transformation matrix -- transformPipeline. GetModelViewProjectionMatrix () to obtain the GetMatrix function on top of the stack can gain matrix value parameter 3: Color (black). * / shaderManager UseStockShader (GLT_SHADER_FLAT, transformPipeline GetModelViewProjectionMatrix (), vBlack); pBatch->Draw(); GlPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glDisable(GL_POLYGON_OFFSET_LINE); GlLineWidth (1.0 f); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); }Copy the code

In this way, we can achieve the effect of our case. Through this case, we can understandThe matrix stackThe operation process of

  • usePushMatrixMethod, which makes a copy of the information at the top of the stack.
  • useMultMatrixMethod to multiply the matrix by the top stack matrix to override the top stack matrix.
  • usePopMatrixRemove the top matrix object when doing a stack operation. (According to the characteristics of the stack, onlypopThe stack)

When we use LoadMatrix to load the matrix to the top of the stack, if no parameter matrix is passed, the element matrix is pushed to the top by default

In the next chapter, we will try to draw a doughnut with OpenGL and solve the problems encountered in it. If you want to know about it, you can pay attention to it.

Remember to like it if you think it’s good! I heard that the people who read the praise will meet the test, meet the prize will be in. ღ(´ · ᴗ · ‘)