OpenGL从入门到放弃(2)—— 正方形的渲染以及键盘控制

552 阅读4分钟

正方形的渲染以及键盘控制

1. 前言

2. 开工

  • 1. 定义正方形的半边长以及四个顶点坐标

        // 正方形参数设置
        GLfloat squareSize = 0.2f;
        GLfloat vVerts[] = {
        -squareSize, -squareSize, 0,
        squareSize, -squareSize, 0,
        squareSize, squareSize, 0,
        -squareSize, squareSize, 0};
    
  • 2. 渲染环境设置

    和之前绘制三角形所使用的GL_TRIANGLES不同,此次使用GL_TRIANGLE_FAN进行正方形的绘制

    // 渲染环境设置
    void setupRC() {
        //设置清屏颜色(背景颜色)
        glClearColor(0.1f, 0.5f, 0.3f, 1);
        
        //没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。初始化一个渲染管理器。
        //使用固定管线渲染,固定着色器
        shaderManager.InitializeStockShaders();

        // 使用GL_TRIANGLE_FAN 该类型进行渲染
        triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
        triangleBatch.CopyVertexData3f(vVerts);
        triangleBatch.End();
    }

Begin方法中不同的类型,代表不同的渲染方法,每一种带来的效果都是不一样的,例如:

```
#define GL_LINE_LOOP 0x0002
#define GL_POINT_BIT 0x00000002
#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002
#define GL_LINE_STRIP 0x0003
#define GL_LINE_BIT 0x00000004
#define GL_TRIANGLES 0x0004
#define GL_TRIANGLE_STRIP 0x0005
#define GL_TRIANGLE_FAN 0x0006
```
  • 3. 开始绘制正方形

renderScene回调中,和绘制三角形一样老一套的几个步骤

    void renderScene(void) {
        //1.清除一个或者一组特定的缓存区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
        
        //2.设置一组浮点数来表示红色 rgba
        GLfloat vRed[] = {0.5,0.6,0.7,1.0};
        
        //传递到存储着色器,即GLT_SHADER_IDENTITY着色器,这个着色器只是使用指定颜色以默认笛卡尔坐标第在屏幕上渲染几何图形
        shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
        
        //提交着色器
        triangleBatch.Draw();

        //将后台缓冲区进行渲染,然后结束后交换给前台
        glutSwapBuffers();
    }
  • 4. 绘制效果

3. 键盘控制正方形移动

  • 1. 这里需要用到新的注册方法glutSpecialFunc

    openGLInit方法的最后,增加注册特殊函数回调,完整的openGLInit方法可以看上一篇项目模版配置

        //注册重塑函数
        glutReshapeFunc(changeSize);
        //注册显示函数
        glutDisplayFunc(renderScene);
        //注册特殊函数
        glutSpecialFunc(specialKeys);
    
    
  • 2. specialKeys方法使用

    // 特殊函数回调
    void specialKeys(int key, int x, int y){
        // 在这里处理响应特殊keys
    }
    
      1. 随意取一个定点当作模版,选取该点的X和Y坐标
      1. 更新4个顶点的坐标(可以使用穷举法或者矩阵更新)
      1. 这里可以添加适当的边界逻辑,这里就不做赘述
      1. 更新完成后,标记当前需要重绘glutPostRedisplay

    更新方式:普通更新,需要对所有的顶点做更新操作

      // 特殊函数回调
      void specialKeys(int key, int x, int y){
          // 设置每一步的距离,就是键盘按一次,图形移动的距离
          GLfloat stepSize = 0.05f;
          
          // 取任意一点的x和y坐标,当作初始坐标
          // 这里取正方形左上角定点的坐标
          GLfloat startX = vVerts[9];
          GLfloat startY = vVerts[10];
          
          // 按键:上
          if (key == GLUT_KEY_UP) {
              startY += stepSize;
          }
          // 按键:下
          if (key == GLUT_KEY_DOWN) {
              startY -= stepSize;
          }
          // 按键:左
          if (key == GLUT_KEY_LEFT) {
              startX -= stepSize;
          }
          // 按键:右
          if (key == GLUT_KEY_RIGHT) {
              startX += stepSize;
          }
          
          // 更新四个顶点坐标, 普通更新方法,顶点数量少时,可以使用
          // 左上角
          vVerts[9] = startX;
          vVerts[10] = startY;
          // 左下角
          vVerts[0] = vVerts[9];
          vVerts[1] = vVerts[10] - squareSize*2;
          // 右下角
          vVerts[3] = vVerts[0] + squareSize*2;
          vVerts[4] = vVerts[1];
          // 右上角
          vVerts[6] = vVerts[3];
          vVerts[7] = vVerts[10];
    
          
          printf("startX = %f, startY = %f\n", startX, startY);
          
          triangleBatch.CopyVertexData3f(vVerts);
          // 标记当前需要重新绘制
          glutPostRedisplay();
      }
    
  • 3. 矩阵更新:适合复杂图形,可操作形更高

      1. 定义全局变量,用来存储移动的距离
          //  矩阵更新需要用到
          GLfloat xPos = 0.0f;
          GLfloat yPos = 0.0f;
      
      1. specialKeys方法中,只需要更新全局属性xPos和yPos即可
      // 特殊函数回调: 矩阵更新
      void specialKeys(int key, int x, int y) {
          // 设置每一步的距离,就是键盘按一次,图形移动的距离
          GLfloat stepSize = 0.05f;
      
          // 按键:上
          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;
          }
      
          // 标记当前需要重新绘制
          glutPostRedisplay();
      }
      
      1. renderScene方法中,进行矩阵更新的设置

      glClear和Draw之间,增加矩阵设置

      void renderScene(void) {
          //1.清除一个或者一组特定的缓存区
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
          
          //2.设置一组浮点数来表示红色 rgba
          GLfloat vRed[] = {0.5,0.6,0.7,1.0};
          
          
          /// 矩阵更新相关
          M3DMatrix44f mFinalTransform,mTransfromMatrix,mRotationMartix;
          //平移
          m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0f);
          //每次平移时,旋转度数
          static float yRot = 0.0f;
          m3dRotationMatrix44(mRotationMartix, m3dDegToRad(yRot), 0.0f, 0.0f, 1.0f);
          //将旋转和移动的矩阵结果 合并到mFinalTransform (矩阵相乘)
          m3dMatrixMultiply44(mFinalTransform, mTransfromMatrix, mRotationMartix);
          //将矩阵结果 提交给固定着色器(平面着色器)中绘制
          shaderManager.UseStockShader(GLT_SHADER_FLAT,mFinalTransform,vRed);
          
          
          //提交着色器
          triangleBatch.Draw();
          //将后台缓冲区进行渲染,然后结束后交换给前台
          glutSwapBuffers();
      }
      
  • 4. 最终移动效果