Draw a square and control the movement effect as follows:



Today use OpenGL to achieve a small case, mainly including the following two parts:
  1. OpenGL draws a square
  2. Special keys control movement

OpenGL draws a square

With this small demo, analyze how the square is rendered to the window

  1. main()Function, program entry, does a few things:
  • Initialize the GLUT library and the double buffering window

  • Set the window size and title

  • Register callback functions (window resizing functions, render functions)

  • The setupRC() function sets up the rendering environment

  • GLUT runs a local message loop internally

Int main(int argc,char *argv[]) {// Set the current working directory, for MAC OS X gltSetWorkingDirectory(argv[0]); GlutInit (&argc, argv); /* Initialize the double buffering window, The symbols GLUT_DOUBLE, GLUT_RGBA, GLUT_DEPTH and GLUT_STENCIL respectively refer to the double buffer window, RGBA color mode, depth test and template buffer */ glutInitDisplayMode(GLUT_DOUBLE|GLUT_DEPTH|GLUT_STENCIL); GlutInitWindowSize (800, 600); glutCreateWindow("Triangle"); GlutReshapeFunc (changeSize); GlutDisplayFunc (RenderScene); // Register the special function glutSpecialFunc(SpecialKeys); /* Initialize a GLEW library to ensure that the OpenGL API is fully available to the program. Before attempting to do any rendering, check to make sure there are no problems with driver initialization */ GLenum status =glewInit();if(status ! = GLEW_OK) {printf("GLEW Error:%s\n",glewGetErrorString(status));
        return1; } // set our render environment setupRC(); glutMainLoop();return  0;
}Copy the code

SetupRC (): a custom function that sets the vertex data/color data associated with the graphics you need to render. Trigger condition: Manually trigger the main function

Handling business:

  1. Sets the window background color
  2. Initialize the storage shader shaderManager
  3. Sets graph vertex data

    // Define the vertex to primordia distance, square side length = blockSize * 2 GLfloatBlockSize = 0.1 f; // The coordinates of the four points of the square GLfloatV] = {-blocksize, -blocksize, 0.0f, blockSize, -blocksize, 0.0f, blockSize, 0.0f, blockSize, 0.0f, -blocksize, BlockSize and 0.0 f,};Copy the code

  4. Data is passed to the shader using the GLBatch square batch class

void setupRC(){// Set the clear color (background color) glClearColor(0, 0, 1, 1); // No rendering can be done in the OpenGL core framework without shaders. Initialize a render manager. shareManager.InitializeStockShaders(); Begin(GL_TRIANGLE_FAN, 4); // Change the connection mode of primitives in setupRC to GL_TRIANGLE_FAN. triangleBatch.CopyVertexData3f(vVerts); triangleBatch.End(); }Copy the code

ChangeSize (): This callback is triggered when the window is first loaded or its size changes, and the redraw operation is triggered within it;

ChangeSize trigger conditions:

  1. A new window
  2. The window size is adjusted. Procedure
Handling business:
  1. Set the OpenGL viewport
  2. Set the OpenGL projection mode

Void changeSize(int w, int h) {/* changeSize(int w, int h) {/* changeSize(int w, int h); }Copy the code

RenderScene() : This function is called when the screen changes or the developer renders actively, and is used to implement the data -> rendering process.

RenderScene trigger conditions:
  1. System automatic trigger
  2. The developer manually invokes the function trigger.
Handling business:
  1. Clear the cache (color, depth, template cache, etc.)
  2. Use storage shaders
  3. Drawing graphics

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) {void RenderScene(void) {void RenderScene(void) {void RenderScene(void) {//1. More than one buffer in OpenGL (color cache, depth cache, and template cache) clears the cache to preset values: GL_COLOR_BUFFER_BIT: indicates the currently active buffer for color writing GL_DEPTH_BUFFER_BIT: indicates the depth buffer GL_STENCIL_BUFFER_BIT: indicates the template buffer */ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); //2. Set a set of floating point numbers to represent red GLfloatVRed [] = {1.0f, 0.0f, 0.0f, 1.0f}; // Pass to the storage shader, GLT_SHADER_IDENTITY shader, This shader is only using the specified color on the screen in a cartesian coordinates by default the first rendering geometry shareManager. UseStockShader (GLT_SHADER_IDENTITY vRed); // Submit the shader triangleBatch.draw (); // When we first set up the openGL window, we specified a double buffer rendering environment. This means that the rendering will be done in the background buffer and then swapped out to the foreground. This prevents the viewer from seeing the rendering process that might be accompanied by flicker from animation frame to animation frame. The buffer switching platform will proceed in a platform-specific manner. GlutSwapBuffers (); }Copy the code

Question: why are the coordinates described as squares in the Demo but not displayed as squares?


  • The answer:

    • Because the standard NDC coordinate system display on the screen is mapped to the window.
    • Your mapped window is (600,800) so it’s not square.
    • Change your mapping window size to (600,600)

Two, special key control movement

SpecialKeys()In:
main()This callback will return a key of type int to determine which key on the keyboard was clicked. This method is used to achieve the effect of the GIF image above.

This effect can be implemented in two ways

  1. Coordinate update mode
  2. The matrix way

Coordinate update mode:


void SpecialKeys(int key, int x, int y) {
    GLfloatStepSize = 0.025 f; GLfloat blockX = vVerts[0];
      GLfloat blockY = vVerts[10];
      
      printf("v[0] = %f\n",blockX);
      printf("v[10] = %f\n",blockY);
      
      
      if (key == GLUT_KEY_UP) {
          
          blockY += stepSize;
      }
      
      if (key == GLUT_KEY_DOWN) {
          
          blockY -= stepSize;
      }
      
      if (key == GLUT_KEY_LEFT) {
          blockX -= stepSize;
      }
      
      if(key == GLUT_KEY_RIGHT) { blockX += stepSize; } // Touch the edges (4 edges) // when the square moves beyond the leftmost edgeif(blockX < -1.0f) {blockX = -1.0f; } // when the square moves to the right //1.0 - blockSize * 2 = total side length - Side length of the square = position of the leftmost pointif(blockX > (1.00-blocksize * 2)) {blockX = 1.0f-blocksize * 2; } // when the square is moved to the bottom //-1.0 - blockSize * 2 = Y (negative axis boundary) - Square side length = position of the bottom pointif(blockY < -1.0f + blockSize * 2) {blockY = -1.0f + blockSize * 2; } // When the square moves to the topif(blockY > 1.0f) {blockY = 1.0f; }printf("blockX = %f\n",blockX);
      printf("blockY = %f\n",blockY);
      
      // Recalculate vertex positions
      vVerts[0] = blockX;
      vVerts[1] = blockY - blockSize*2;
      printf("(%f,%f)\n",vVerts[0],vVerts[1]);
      
      vVerts[3] = blockX + blockSize*2;
      vVerts[4] = blockY - blockSize*2;
      printf("(%f,%f)\n",vVerts[3],vVerts[4]);
      
      vVerts[6] = blockX + blockSize*2;
      vVerts[7] = blockY;
      printf("(%f,%f)\n",vVerts[6],vVerts[7]);
      
      vVerts[9] = blockX;
      vVerts[10] = blockY;
      printf("(%f,%f)\n",vVerts[9],vVerts[10]);
      
      triangleBatch.CopyVertexData3f(vVerts);
      
      glutPostRedisplay();
}Copy the code

Matrix mode:

Define two global variables (translation distance relative to x and y axes)

GLfloatXPos = 0.0 f; GLfloatYPos = 0.0 f;Copy the code

The key controls movement

void SpecialKeys(int key, int x, int y){
    
   
    
    GLfloatStepSize = 0.025 f;if (key == GLUT_KEY_UP) {
        
        yPos += stepSize;
    }
    
    if (key == GLUT_KEY_DOWN) {
        yPos -= stepSize;
    }
    
    if (key == GLUT_KEY_LEFT) {
        xPos -= stepSize;
    }
    
    if(key == GLUT_KEY_RIGHT) { xPos += stepSize; } // Collision detectionif(xPos < (-1.0f + blockSize)) {xPos = -1.0f + blockSize; }if(xPos > (1.0f-blocksize)) {xPos = 1.0f-blocksize; }if(yPos < (-1.0f + blockSize)) {yPos = -1.0f + blockSize; }if(yPos > (1.0f-blocksize)) {yPos = 1.0f-blocksize; } glutPostRedisplay(); }Copy the code

To render

Void RenderScene(void) {//1. Remove one or a set of specific buffer glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //1. Set color RGBA GLfloatVRed [] = {1.0f, 0.5f, 0.0f, 1.0f}; // Define matrix M3DMatrix44f mTransformMatrix; // m3dTranslationMatrix44(mTransformMatrix, xPos, yPos, 0.0f); // When cell shaders are not enough, use flat shaders // Parameter 1: storage shader type // Parameter 2: what matrix transformation to use // parameter 3: Color shaderManager. UseStockShader (GLT_SHADER_FLAT mTransformMatrix, vRed); // Submit the shader triangleBatch.draw (); glutSwapBuffers(); }Copy the code


Overall flow chart:

To be updated


Attached: Github complete Demo

03-OpenGL- Draw square keyboard control movement (coordinate update)

04-OpenGL- Draw square keyboard Control (Matrix)