OpenGL入门-绘制正方形案例分析

402 阅读5分钟
  • 主要工具类

    1. 着色器管理类

    2. GLTools函数

    3. freeglut静态库

      三者的作用如下表:

      名称 引用头文件 作用说明
      着色器管理 #include "GLShaderManager.h" #include<GLShaderManager.h>` 移入了GLTool 着色器管理器(shader Mananger)类。没有着色器,我们就不能在OpenGL(核心框架)进行着色。着色器管理器不仅允许我们创建并管理着色器,还提供一组“存储着色器”,他们能够进行一些初步䄦基本的渲染操作。
      GLTools函数 #include "GLTools.h" GLTools是基于GLEW库的,也就是说GLTools里面是封装了GLEW库的,这样我们就不用include<glew.h>而是include<GLTools.h>就可以了。GLTools里封装了用于操作矩阵和向量的3D数学库,并且有默认的shader可以渲染简单的3D对象数
      freeglut静态库 #include <GLUT/GLUT.h> 可以理解为glut的替代库主要包括窗口操作函数,窗口初始化、窗口大小、窗口位置等函数;回调函数:响应刷新消息、键盘消息、鼠标消息等等
  • 主要函数

    1. setupRC()(设置渲染环境)

      • 执行时机:绘制前只执行一次
      • 主要作用:设置背景颜色,初始化渲染管理器(这里使用的是固定管线),设置定点数据并通过GLBatch批次容器提交给固定管线
      • 相关代码:
      //定义一个,着色管理器
      GLShaderManager shaderManager;
      //简单的批次容器,是GLTools的一个简单的容器类。
      GLBatch triangleBatch;
      //blockSize 边长
      GLfloat blockSize = 0.1f;
      
      //正方形的4个点坐标(应为两个点是重合的所以是四个点)
      GLfloat vVerts[] = {
              -blockSize,-blockSize,0.0f,
              blockSize,-blockSize,0.0f,
              blockSize,blockSize,0.0f,
              -blockSize,blockSize,0.0f
      };
      
      
      GLfloat xPos = 0.0f;
      GLfloat yPos = 0.0f;
      
      void setupRC()
      {
          //设置清屏颜色(背景颜色)
          glClearColor(0.98f, 0.40f, 0.7f, 1);
          
          
          //没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。初始化一个渲染管理器。
          shaderManager.InitializeStockShaders();
          
          
          //指定顶点
          //在OpenGL中,三角形是一种基本的3D图元绘图原素。
          GLfloat vVerts[] = {
              -0.5f,0.0f,0.0f,
              0.5f,0.0f,0.0f,
              0.0f,0.5f,0.0f
          };
          
          triangleBatch.Begin(GL_TRIANGLES, 3);
          triangleBatch.CopyVertexData3f(vVerts);
          triangleBatch.End();
          
      }
      
    2. changeSize(int w,int h)

      • 执行时机:在窗口大小改变时
      • 作用:接受窗口的宽高并设置窗口
      • 相关代码:
      /*
       在窗口大小改变时,接收新的宽度&高度。
       */
      void changeSize(int w,int h)
      {
          /*
            x,y 参数代表窗口中视图的左下角坐标,而宽度、高度是像素为表示,通常x,y 都是为0
           */
          glViewport(0, 0, w, h);
          
      }
      
    3. RenderScene()

      • 执行时机:需要显示渲染时调用
      • 作用:渲染工作(清楚缓冲区、设置颜色、传递给存储着色器、提交着色器、绘制)
      • 相关代码:
      void RenderScene(void)
      {
      
          //1.清除一个或者一组特定的缓存区
          /*
           缓冲区是一块存在图像信息的储存空间,红色、绿色、蓝色和alpha分量通常一起分量通常一起作为颜色缓存区或像素缓存区引用。
           OpenGL 中不止一种缓冲区(颜色缓存区、深度缓存区和模板缓存区)
            清除缓存区对数值进行预置
           参数:指定将要清除的缓存的
           GL_COLOR_BUFFER_BIT :指示当前激活的用来进行颜色写入缓冲区
           GL_DEPTH_BUFFER_BIT :指示深度缓存区
           GL_STENCIL_BUFFER_BIT:指示模板缓冲区
           */
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
          
          //2.设置一组浮点数来表示红色
          GLfloat vRed[] = {1.0,0.50,0.0,0.5f};
          
          M3DMatrix44f mTransfromMatrix;
          //平移
          m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0f);
          
          //传递到存储着色器,即GLT_SHADER_IDENTITY着色器,这个着色器只是使用指定颜色以默认笛卡尔坐标第在屏幕上渲染几何图形
          shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
          
          //提交着色器
          triangleBatch.Draw();
          
          //在开始的设置openGL 窗口的时候,我们指定要一个双缓冲区的渲染环境。这就意味着将在后台缓冲区进行渲染,渲染结束后交换给前台。这种方式可以防止观察者看到可能伴随着动画帧与动画帧之间的闪烁的渲染过程。缓冲区交换平台将以平台特定的方式进行。
          //将后台缓冲区进行渲染,然后结束后交换给前台
          glutSwapBuffers();
          
      }
      
      
    4. SpecialKeys(监听键盘触发函数)

      • 执行时机:点击键盘按钮
      • 左右:监听键盘实现上下左右平移
      • 相关代码:
      void SpecialKeys(int key, int x, int y){
          
         
          
          GLfloat stepSize = 0.025f;
          
          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;
          }
          
          //碰撞检测
          if (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();
          
      }
      
    5. *main(int argc,char argv[])(程序入口函数,初始化工作)

      • 执行时机:程序初次运行
      • 作用:初始化GLUT库、初始化双缓冲窗口、GLUT窗口大小、窗口标题、注册重塑函数、注册显示函数、初始化一个GLEW库、设置我们的渲染环境、启动一个类似runLoop的循环
      • 相关代码:
      int main(int argc,char *argv[])
      {
      
          //初始化GLUT库,这个函数只是传说命令参数并且初始化glut库
          glutInit(&argc, argv);
          
          /*
           初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
           双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区
           
           --GLUT_DOUBLE`:双缓存窗口,是指绘图命令实际上是离屏缓存区执行的,然后迅速转换成窗口视图,这种方式,经常用来生成动画效果;
           --GLUT_DEPTH`:标志将一个深度缓存区分配为显示的一部分,因此我们能够执行深度测试;
           --GLUT_STENCIL`:确保我们也会有一个可用的模板缓存区。
           深度、模板测试后面会细致讲到
           */
          glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
          
          //GLUT窗口大小、窗口标题
          glutInitWindowSize(800, 600);
          glutCreateWindow("Triangle");
          
          /*
           GLUT 内部运行一个本地消息循环,拦截适当的消息。然后调用我们不同时间注册的回调函数。我们一共注册2个回调函数:
           1)为窗口改变大小而设置的一个回调函数
           2)包含OpenGL 渲染的回调函数
           */
          //注册重塑函数
          glutReshapeFunc(changeSize);
          //注册显示函数
          glutDisplayFunc(RenderScene);
          //注册特殊函数
          glutSpecialFunc(SpecialKeys);
      
          /*
           初始化一个GLEW库,确保OpenGL API对程序完全可用。
           在试图做任何渲染之前,要检查确定驱动程序的初始化过程中没有任何问题
           */
          GLenum status = glewInit();
          if (GLEW_OK != status) {
              
              printf("GLEW Error:%s\n",glewGetErrorString(status));
              return 1;
              
          }
          
          //设置我们的渲染环境
          setupRC();
          glutMainLoop();
       
          return  0;
          
      }
      
  • 函数执行流程图

  • 函数执行效果