I. Case Effect:

The local case is a summary of the previous learning, the implementation steps are as follows:

Draw the floor -> Draw the ball -> Rotate the ball around the ball -> move the observer

The final effect is as follows:

Ii. Code parsing:

The code flow is the same as before, and the previous several functions will still be used. If you forget or have no impression, you can read this articleportalSo let’s get started

1. Finish the floor drawing

This step is familiar with the previous case should be relatively simple answer, we want to achieve the effect is to draw a grid floor with green lines, the effect picture is as follows:The code is as follows:

//001-- General training (floor) GLShaderManager; // GLMatrixStack modelViewMatrix; // model view matrix GLMatrixStack projectionMatrix; // GLFrustum viewFrustum; // GLGeometryTransform transformPipeline; // GLTriangleBatch torusBatch; // GLTriangleBatch sphereBatch; // GLBatch floorBatch; // floor // role frame camera role frame GLFrame cameraFrame; #define NUM_SPHERES 50 GLFrame spheres[NUM_SPHERES]; Void SetupRC() {//1. Initialize glClearColor(0.0f, 0.0f, 0.0f, 1.0f); shaderManager.InitializeStockShaders(); //2. Enable depth test glEnable(GL_DEPTH_TEST); Begin(GL_LINES, 324); For (GLfloat x = 20.0; X < = 20.0 f; X += 0.5) {floorBatch.vertex3f (x, -0.55f, 20.0f); FloorBatch. Vertex3f (x, - 0.55 f, 20.0 f); FloorBatch. Vertex3f (20.0 f to 0.55 f, x); FloorBatch. Vertex3f (20.0 f, 0.55 f, x); } floorBatch.End(); } // call to draw the scene void RenderScene(void) {//1. Static GLfloat vFloorColor[] = {0.0f, 1.0f, 0.0f, 1.0f}; / / 2. Remove the color buffer and depth buffer glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); / / 3. Draw the ground shaderManager. UseStockShader (GLT_SHADER_FLAT, transformPipeline GetModelViewProjectionMatrix (), vFloorColor); floorBatch.Draw(); GlutSwapBuffers (); Void ChangeSize(int nWidth, int nHeight) {//1. Set the viewport glViewport(0, 0, nWidth, nHeight); //2. Create a projection matrix. ViewFrustum. SetPerspective (35.0 f, float (nWidth)/float (nHeight), 1.0 f, 100.0 f); / / viewFrustum. GetProjectionMatrix () to obtain viewFrustum projection matrix / / and loads it into the projection matrix on the stack projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); Set up transformPipeline to use two matrix stacks (transform matrix modelViewMatrix, projectionMatrix projectionMatrix) // initialize GLGeometryTransform instance transformPipeline. Initialize it by setting its internal Pointers to the model view matrix stack and projection matrix stack instances // of course this can also be done in the SetupRC function, but it does no harm to set them when the window size changes or when the window is created. And you can set up the matrix and pipeline all at once. transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix); } int main(int argc, char* argv[]) { gltSetWorkingDirectory(argv[0]); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); GlutInitWindowSize (800600); glutCreateWindow("OpenGL SphereWorld"); glutReshapeFunc(ChangeSize); glutDisplayFunc(RenderScene); GLenum err = glewInit(); if (GLEW_OK ! = err) { fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); return 1; } SetupRC(); glutMainLoop(); return 0; }Copy the code

2. Draw large balls

This step involves modifying the setupRC and RenderSence code:

  • setupRCThe code is very simple, just complete the creation of large, small ball model:
Void SetupRC() {//1. Initialize glClearColor(0.0f, 0.0f, 0.0f, 1.0f); shaderManager.InitializeStockShaders(); //2. Enable depth test glEnable(GL_DEPTH_TEST); Begin(GL_LINES, 324); For (GLfloat x = 20.0; X < = 20.0 f; X += 0.5) {floorBatch.vertex3f (x, -0.55f, 20.0f); FloorBatch. Vertex3f (x, - 0.55 f, 20.0 f); FloorBatch. Vertex3f (20.0 f to 0.55 f, x); FloorBatch. Vertex3f (20.0 f, 0.55 f, x); } floorBatch.End(); Makesphere (torusBatch, 0.4f, 40, 80); GltMakeSphere (sphereBatch, 0.1F, 13, 26); For (int I = 0; i < NUM_SPHERES; GLfloat X = ((GLfloat)((rand() % 400) -200) * 0.1f); GLfloat z = ((GLfloat)((rand() % 400) -200) * 0.1f); // For each vertex in the Spheres array, set the vertex data Spheres [I].SetOrigin(x, 0.0f, z); // For each vertex in the spheres array, set the vertex data Spheres [I]. }}Copy the code
  • RenderSenceIs mainly responsible for the completion of the large ball drawing, and the correlation matrix for the stack and out of the stack. For those unfamiliar with the matrix stack, check out the article portal (www.jianshu.com/p/26e05a4fd…

)

Void RenderScene(void) {//1. Static GLfloat vFloorColor[] = {0.0f, 1.0f, 0.0f, 1.0f}; Static GLfloat vTorusColor[] = {1.0f, 0.5f, 0.0f, 1.0f}; static GLfloat vTorusColor[] = {1.0f, 0.5f, 0.0f, 1.0f}; Static GLfloat vSphereColor[] = {0.0f, 0.5f, 1.0f, 1.0f}; //2. Time-based animation static CStopWatch rotTimer; Float yRot = rotTimer. GetElapsedSeconds () * 60.0 f; / / 3. Clear the color buffer and depth buffer glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); modelViewMatrix.PushMatrix(); / / 4. Draw the ground shaderManager. UseStockShader (GLT_SHADER_FLAT, transformPipeline GetModelViewProjectionMatrix (), vFloorColor); floorBatch.Draw(); M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f}; / / 6. Translation makes the ball position (3.0) to the screen inside modelViewMatrix. Translate (0.0 f to 0.0 f, 3.0 f); / / 7. Pressure stack (copy stack) modelViewMatrix. PushMatrix (); Rotate(yRot, 0.0f, 0.0f, 0.0f); Rotate(yRot, 0.0f, 0.0f); Rotate(yRot, 0.0f, 0.0f); / / 9. Specify the proper shader (point source shader) shaderManager. UseStockShader (GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline GetModelViewMatrix (), transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor); torusBatch.Draw(); / / 10. Finished drawing the Pop modelViewMatrix. PopMatrix (); For (int I = 0; i < NUM_SPHERES; i++) { modelViewMatrix.PushMatrix(); modelViewMatrix.MultMatrix(spheres[i]); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor); sphereBatch.Draw(); modelViewMatrix.PopMatrix(); } modelViewMatrix.PopMatrix(); GlutSwapBuffers (); glutPostRedisplay(); }Copy the code

Run it and the result is as follows:

3. The rotation of the large ball and the rotation of the small ball around the large ball:

In this step, we only need to modify part of the RenderSence code:

Void RenderScene(void) {//1. Static GLfloat vFloorColor[] = {0.0f, 1.0f, 0.0f, 1.0f}; Static GLfloat vTorusColor[] = {1.0f, 0.5f, 0.0f, 1.0f}; static GLfloat vTorusColor[] = {1.0f, 0.5f, 0.0f, 1.0f}; Static GLfloat vSphereColor[] = {0.0f, 0.5f, 1.0f, 1.0f}; //2. Time-based animation static CStopWatch rotTimer; Float yRot = rotTimer. GetElapsedSeconds () * 60.0 f; / / 3. Clear the color buffer and depth buffer glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); modelViewMatrix.PushMatrix(); / / 5. Draw the ground shaderManager. UseStockShader (GLT_SHADER_FLAT, transformPipeline GetModelViewProjectionMatrix (), vFloorColor); floorBatch.Draw(); M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f}; / / 7. Translation makes the ball position (3.0) to the screen inside modelViewMatrix. Translate (0.0 f to 0.0 f, 3.0 f); / / 8. Pressure stack (copy stack) modelViewMatrix. PushMatrix (); Rotate(yRot, 0.0f, 0.0f, 0.0f); Rotate(yRot, 0.0f, 0.0f); Rotate(yRot, 0.0f, 0.0f); / / 10. Specify the proper shader (point source shader) shaderManager. UseStockShader (GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline GetModelViewMatrix (), transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor); torusBatch.Draw(); / / 11. Finished drawing the Pop modelViewMatrix. PopMatrix (); For (int I = 0; i < NUM_SPHERES; i++) { modelViewMatrix.PushMatrix(); modelViewMatrix.MultMatrix(spheres[i]); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor); sphereBatch.Draw(); modelViewMatrix.PopMatrix(); Rotate modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f); Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f); ModelViewMatrix. Translate (0.8 f, f 0.0, 0.0 f); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetPro jectionMatrix(),vLightPos,vSphereColor); sphereBatch.Draw(); modelViewMatrix.PopMatrix(); GlutSwapBuffers (); glutPostRedisplay(); }Copy the code
  • The running results are as follows:

It is worth noting that we did not do the matrix stack operation when we made the blue ball revolve, because the blue ball is the last drawing of all the graphics, after which we willpopDrop all matrices in the matrix stack, so you can leave it out of the matrixpushandpopOf course, you can also choose to increasepushandpopBut please note that the location must be correct.

The code is as follows:

modelViewMatrix.PushMatrix(); ModelViewMatrix.Rotate(yRot * -1.0f, 0.0f, 1.0f, 0.0f); ModelViewMatrix. Translate (0.8 f, f 0.0, 0.0 f); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetPro jectionMatrix(),vLightPos,vSphereColor); sphereBatch.Draw(); modelViewMatrix.PopMatrix();Copy the code

4. Add movement logic

  • inmainRegister in a functionSpeacialKeysFunction:
glutSpecialFunc(SpeacialKeys);
Copy the code
  • Then, inSpeacialKeys To achieve the control of the upper, lower, and left keys on the observer:
Void SpeacialKeys(int key,int x,int y){float linear = 0.1f; Float Angular = float(m3dDegToRad(5.0f)); If (key == GLUT_KEY_UP) {//MoveForward move camerafame. } if (key == GLUT_KEY_DOWN) { cameraFrame.MoveForward(-linear); } if (key == GLUT_KEY_LEFT) {RotateWorld rotate camerafame.RotateWorld(Angular, 0.0f, 1.0f, 0.0f); } if (key == GLUT_KEY_RIGHT) {camerafame.RotateWorld(-Angular, 0.0f, 1.0f, 0.0f); }}Copy the code
  • inRenderSenceAdd the observer to the matrix stackpushandpopOperation:
Void RenderScene(void) {//1. Static GLfloat vFloorColor[] = {0.0f, 1.0f, 0.0f, 1.0f}; Static GLfloat vTorusColor[] = {1.0f, 0.5f, 0.0f, 1.0f}; static GLfloat vTorusColor[] = {1.0f, 0.5f, 0.0f, 1.0f}; Static GLfloat vSphereColor[] = {0.0f, 0.5f, 1.0f, 1.0f}; //2. Time-based animation static CStopWatch rotTimer; Float yRot = rotTimer. GetElapsedSeconds () * 60.0 f; / / 3. Clear the color buffer and depth buffer glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); modelViewMatrix.PushMatrix(); //4. Add observer pan 10 steps (floor, large ball, small ball, small ball) M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.PushMatrix(mCamera); M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f}; / / 6. Draw the ground shaderManager. UseStockShader (GLT_SHADER_FLAT, transformPipeline GetModelViewProjectionMatrix (), vFloorColor); floorBatch.Draw(); // the default position of the big ball (0,0,0) is Z depth (3.0). Plus and minus refer to the direction, and the number refers to the distance traveled. Makes the ball position in translation (3.0) to the screen move only 1 times modelViewMatrix. Translate (0.0 f to 0.0 f, 3.0 f); / / 8. Pressure stack (copy stack) modelViewMatrix. PushMatrix (); Rotate(yRot, 0.0f, 0.0f, 0.0f); Rotate(yRot, 0.0f, 0.0f); Rotate(yRot, 0.0f, 0.0f); / / 10. Specify the proper shader (point source shader) shaderManager. UseStockShader (GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline GetModelViewMatrix (), transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor); torusBatch.Draw(); / / 11. Finished drawing the Pop modelViewMatrix. PopMatrix (); For (int I = 0; i < NUM_SPHERES; i++) { modelViewMatrix.PushMatrix(); modelViewMatrix.MultMatrix(spheres[i]); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor); sphereBatch.Draw(); modelViewMatrix.PopMatrix(); Rotate modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f); Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f); ModelViewMatrix. Translate (0.8 f, f 0.0, 0.0 f); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetPro jectionMatrix(),vLightPos,vSphereColor); sphereBatch.Draw(); modelViewMatrix.PopMatrix(); modelViewMatrix.PopMatrix(); GlutSwapBuffers (); //15 glutPostRedisplay(); }Copy the code

Ok, then run the project, press up, down, left and right, and the observer will move accordingly.

5. Complete code:

GLShaderManager shaderManager; // GLMatrixStack modelViewMatrix; // model view matrix stack GLMatrixStack projectionMatrix; // Stack GLFrustum viewFrustum; // GLGeometryTransform transformPipeline; // GLTriangleBatch torusBatch; // GLTriangleBatch sphereBatch; // GLBatch floorBatch; // floor // role frame camera role frame GLFrame cameraFrame; GLFrame objectFrame; #define NUM_SPHERES 50 GLFrame spheres[NUM_SPHERES]; Void SetupRC() {//1. Initialize glClearColor(0, 0, 0, 1); shaderManager.InitializeStockShaders(); glEnable(GL_DEPTH_TEST); Floorbatch.begin (GL_LINES, 324); For (GLfloat x = 20.0; X < = 20.0 f; X += 0.5) {floorBatch.vertex3f (x, -0.55f, 20.0f); FloorBatch. Vertex3f (x, - 0.55 f, 20.0 f); FloorBatch. Vertex3f (20.0 f to 0.55 f, x); FloorBatch. Vertex3f (20.0 f, 0.55 f, x); } floorBatch.End(); GltMakeSphere (torusBatch, 0.4f, 40, 80); //5. Draw the ball; GltMakeSphere (sphereBatch, 0.1 f, 30, 60). For (int I = 0; i < NUM_SPHERES; GLfloat X = ((GLfloat)((rand() % 400) -200) * 0.1f); GLfloat z = ((GLfloat)((rand() % 400) -200) * 0.1f); // For each vertex in the Spheres array, set the vertex data Spheres [I].SetOrigin(x, 0.0f, z); // For each vertex in the spheres array, set the vertex data Spheres [I]. }} call / / to draw the scene void RenderScene (void) {/ / 3. GlClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); Static GLfloat vFloorColor[] = {0.0f,1.0f,0.0f,1.0f}; Static GLfloat vTorusColor[] = {1.0f,0.5f,0.0f,1.0f}; static GLfloat vTorusColor[] = {1.0f,0.5f,0.0f,1.0f}; Static GLfloat vSpereColor[] = {0.0f,0.5f,1.0f,1.0f}; //2. Animation static CStopWatch rotTimer; Float yRot = rotTimer. GetElapsedSeconds () * 60.0 f; modelViewMatrix.PushMatrix(); M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.PushMatrix(mCamera); //4. shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor); floorBatch.Draw(); M3DVector4f vLightPos = {0,10,5,1}; / / 6. Make the whole ball into translational modelViewMatrix. 3.0 Translate (0.0 f, f 0.0, 3.0 f); / / 7. Ball modelViewMatrix. PushMatrix (); modelViewMatrix.Rotate(yRot, 0, 1, 0); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetPro jectionMatrix(),vLightPos,vTorusColor); torusBatch.Draw(); modelViewMatrix.PopMatrix(); For (int I = 0; i < NUM_SPHERES; i++) { modelViewMatrix.PushMatrix(); modelViewMatrix.MultMatrix(spheres[i]); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetPro jectionMatrix(),vLightPos,vSpereColor); sphereBatch.Draw(); modelViewMatrix.PopMatrix(); } //9. Move a small ball around a larger one; ModelViewMatrix.Rotate(yRot * -2.0f, 0, 1, 0); ModelViewMatrix. Translate (0.8 f, f 0.0, 0.0 f); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetPro jectionMatrix(),vLightPos,vSpereColor); sphereBatch.Draw(); modelViewMatrix.PopMatrix(); modelViewMatrix.PopMatrix(); glutSwapBuffers(); glutPostRedisplay(); } void ChangeSize(int nWidth, int nHeight) {//1. Set the viewport glViewport(0, 0, nWidth, nHeight); / / 2. Create the projection matrix viewFrustum. SetPerspective (35.0 f, float (nWidth)/float (nHeight), 1.0 f, 100.0 f); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); / / 3. The two matrices transformation pipeline setting stack (management) transformPipeline. SetMatrixStacks (modelViewMatrix projectionMatrix); } void SpeacialKeys(int key,int x,int y){float linear = 0.1f; Float presents = float (m3dDegToRad (5.0 f)); if (key == GLUT_KEY_UP) { cameraFrame.MoveForward(linear); } if (key == GLUT_KEY_DOWN) { cameraFrame.MoveForward(-linear); } if (key == GLUT_KEY_LEFT) { cameraFrame.RotateWorld(angular, 0, 1, 0); } if (key == GLUT_KEY_RIGHT) { cameraFrame.RotateWorld(-angular, 0, 1, 0); } } int main(int argc, char* argv[]) { gltSetWorkingDirectory(argv[0]); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); GlutInitWindowSize (800600); glutCreateWindow("OpenGL SphereWorld"); glutReshapeFunc(ChangeSize); glutDisplayFunc(RenderScene); glutSpecialFunc(SpeacialKeys); GLenum err = glewInit(); if (GLEW_OK ! = err) { fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); return 1; } SetupRC(); glutMainLoop(); return 0; }Copy the code

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. ღ(´ · ᴗ · ‘)