• OpenGL 五


    /* 最新更新时间 2020-07-20 

     增加:矩阵压栈

    */

    /*****************************************************************/

    我们视觉上的物体的移动有2种方式:

    1、物体移动,观察者(眼睛)不动;

    2、物体不动,观察者移动。

    案例代码分析 -- 点线、金字塔、六边形、圆环的绘制

    一、物体移动

    1、物体移动,观察者不动

     1 // 绘制
     2 void RenderScene(void) {
     3     
     4     // Clear the window with current clearing color
     5     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);// 清空
     6    
     7     // 压栈
     8     modelViewMatrix.PushMatrix();
     9 
    10     // 观察者矩阵
    11     M3DMatrix44f mCamera;
    12     cameraFrame.GetCameraMatrix(mCamera);
    13     // 单元矩阵 * 观察者矩阵 --> new观察者矩阵 
    14     // 矩阵 * 矩阵堆栈的顶部矩阵,相乘的结果随后 存储在堆栈的顶部
    15     modelViewMatrix.MultMatrix(mCamera);// new观察者矩阵 压栈
    16     
    17     // 物体矩阵
    18     M3DMatrix44f mObjectFrame;
    19     // 只要使用 GetMatrix 函数就可以获取矩阵堆栈顶部的值,这个函数可以进行2次重载。用来使用 GLShaderManager 的使用,或者是获取顶部矩阵的顶点副本数据
    20     objectFrame.GetMatrix(mObjectFrame);
    21     // new观察者矩阵 * 物体矩阵 --> 模型视图矩阵,相乘的结果随后 存储在堆栈的顶部
    22     modelViewMatrix.MultMatrix(mObjectFrame);// 模型视图矩阵 压栈
    23     
    24     /*** GLShaderManager 中的 Uniform 值——平面着色器
    25      参数1:平面着色器
    26      参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
    27      --transformPipeline.GetModelViewProjectionMatrix() 获取的
    28      GetMatrix函数就可以获得矩阵堆栈顶部的值
    29      参数3:颜色值(黑色)
    30      */
    31     shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    32     
    33     switch(nStep) {
    34         case 0:
    35             // 设置点的大小
    36             glPointSize(4.0f);
    37             pointBatch.Draw();
    38             glPointSize(1.0f);
    39             break;
    40         case 1:
    41             // 设置线的宽度
    42             glLineWidth(2.0f);
    43             lineBatch.Draw();
    44             glLineWidth(1.0f);
    45             break;
    46         case 2:
    47             glLineWidth(2.0f);
    48             lineStripBatch.Draw();
    49             glLineWidth(1.0f);
    50             break;
    51         case 3:
    52             glLineWidth(2.0f);
    53             lineLoopBatch.Draw();
    54             glLineWidth(1.0f);
    55             break;
    56         case 4:
    57             DrawWireFramedBatch(&triangleBatch);
    58             break;
    59         case 5:
    60             DrawWireFramedBatch(&triangleStripBatch);
    61             break;
    62         case 6:
    63             DrawWireFramedBatch(&triangleFanBatch);
    64             break;
    65     }
    66     
    67     // 出栈 还原到初始的模型视图矩阵(单位矩阵)
    68     modelViewMatrix.PopMatrix();
    69     
    70     // 进行缓冲区交换
    71     glutSwapBuffers();
    72 }

    上面代码中的 2 次压栈,单元矩阵 -- 观察者矩阵 相乘 --> new观察者矩阵 -- 物体矩阵 相乘 --> 模型视图矩阵,平面着色器绘制。

    物体的展示做了如下的流程转换: 物体坐标(object space) --> 世界坐标 --> 观察者坐标 --> 裁剪坐标(clip space),再经过OpenGL转化 --> 规范化设备坐标(DNC space) --> 显示在屏幕上。

    2、物体不动,观察者动

    主要代码

     1 // 绘制
     2 void RenderScene(void) {// 观察者移动
     3 
     4     // Clear the window with current clearing color
     5     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
     6    
     7     // 压栈
     8     modelViewMatrix.PushMatrix(objectFrame);// 将观察者矩阵压入视图模型矩阵中
     9     /* GLShaderManager 中的Uniform 值——平面着色器
    10      参数1:平面着色器
    11      参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
    12      --transformPipeline.GetModelViewProjectionMatrix() 获取的
    13      GetMatrix函数就可以获得矩阵堆栈顶部的值
    14      参数3:颜色值(黑色)
    15      */
    16     shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    17     
    18     switch(nStep) {
    19         case 0:
    20             //设置点的大小
    21             glPointSize(4.0f);
    22             pointBatch.Draw();
    23             glPointSize(1.0f);
    24             break;
    25         case 1:
    26             //设置线的宽度
    27             glLineWidth(2.0f);
    28             lineBatch.Draw();
    29             glLineWidth(1.0f);
    30             break;
    31         case 2:
    32             glLineWidth(2.0f);
    33             lineStripBatch.Draw();
    34             glLineWidth(1.0f);
    35             break;
    36         case 3:
    37             glLineWidth(2.0f);
    38             lineLoopBatch.Draw();
    39             glLineWidth(1.0f);
    40             break;
    41         case 4:
    42             DrawWireFramedBatch(&triangleBatch);
    43             break;
    44         case 5:
    45             DrawWireFramedBatch(&triangleFanBatch);
    46             break;
    47         case 6:
    48             DrawWireFramedBatch(&triangleStripBatch);
    49             break;
    50     }
    51     
    52     //还原到以前的模型视图矩阵(单位矩阵)
    53     modelViewMatrix.PopMatrix();
    54     
    55     // 进行缓冲区交换
    56     glutSwapBuffers();
    57 }

    疑问:为什么 观察者移动时只把一个观察者矩阵压栈,而没有像物体移动时进行矩阵混合计算呢???

    个人的理解如下(如有理解偏差,请大家帮忙指正,谢谢):

      1、当观察者固定,物体移动时,物体的每个点位都是需要做相应的移动的,矩阵计算即:移动物体时我们每次都要计算的每个点的位置并使之移动。(例子:我们移动一个平面的正方形,每移动一步,正方形的4个点我们都要对其位置进行计算并移动)。

      2、当物体固定,观察者移动时,相当于我们的眼睛在动,此时的移动就只有眼睛位置这一个移动,我们要做的就是表明眼睛的所在位置即可。

    简单可归结为:物体移动,则物体本身上的每个位置都要进行移动;观察者移动,移动的只是眼睛的位置。

    二、图形的绘制

    点 线 面、金字塔、圆环、扇形

      1 // 初始化
      2 void SetupRC() {
      3 
      4     // 灰色的背景
      5     glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
      6     shaderManager.InitializeStockShaders();
      7     glEnable(GL_DEPTH_TEST);
      8     //设置变换管线以使用两个矩阵堆栈
      9     transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
     10     cameraFrame.MoveForward(-15.0f);
     11     
     12     /*
     13      常见函数:
     14      void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);
     15       参数1:表示使用的图元
     16       参数2:顶点数
     17       参数3:纹理坐标(可选)
     18      
     19      //负责顶点坐标
     20      void GLBatch::CopyVertexData3f(GLFloat *vNorms);
     21      
     22      //结束,表示已经完成数据复制工作
     23      void GLBatch::End(void);
     24      */
     25     // 定义三角形形状 的点
     26     GLfloat vCoast[9] = {
     27         3,3,0,0,3,0,3,0,0
     28     };
     29     
     30     // 不同方式 三角
     31     // 1、用点的形式
     32     pointBatch.Begin(GL_POINTS, 3);
     33     pointBatch.CopyVertexData3f(vCoast);
     34     pointBatch.End();
     35     
     36     // 2、通过线的形式
     37     lineBatch.Begin(GL_LINES, 3);
     38     lineBatch.CopyVertexData3f(vCoast);
     39     lineBatch.End();
     40     
     41     // 3、通过线段的形式
     42     lineStripBatch.Begin(GL_LINE_STRIP, 3);
     43     lineStripBatch.CopyVertexData3f(vCoast);
     44     lineStripBatch.End();
     45     
     46     // 4、通过线环的形式
     47     lineLoopBatch.Begin(GL_LINE_LOOP, 3);
     48     lineLoopBatch.CopyVertexData3f(vCoast);
     49     lineLoopBatch.End();
     50     
     51 
     52     // 5、通过三角形创建金字塔
     53     GLfloat vPyramid[12][3] = {
     54         -2.0f, 0.0f, -2.0f,
     55         2.0f, 0.0f, -2.0f,
     56         0.0f, 4.0f, 0.0f,
     57 
     58         2.0f, 0.0f, -2.0f,
     59         2.0f, 0.0f, 2.0f,
     60         0.0f, 4.0f, 0.0f,
     61 
     62         2.0f, 0.0f, 2.0f,
     63         -2.0f, 0.0f, 2.0f,
     64         0.0f, 4.0f, 0.0f,
     65 
     66         -2.0f, 0.0f, 2.0f,
     67         -2.0f, 0.0f, -2.0f,
     68         0.0f, 4.0f, 0.0f
     69         
     70     };
     71 //    GLfloat vPyramid[12][3] = {
     72 //        -4.0f, 0.0f, -4.0f,
     73 //        4.0f, 0.0f, -4.0f,
     74 //        0.0f, 8.0f, 0.0f,
     75 //
     76 //        4.0f, 0.0f, -4.0f,
     77 //        4.0f, 0.0f, 4.0f,
     78 //        0.0f, 8.0f, 0.0f,
     79 //
     80 //        4.0f, 0.0f, 4.0f,
     81 //        -4.0f, 0.0f, 4.0f,
     82 //        0.0f, 8.0f, 0.0f,
     83 //
     84 //        -4.0f, 0.0f, 4.0f,
     85 //        -4.0f, 0.0f, -4.0f,
     86 //        0.0f, 8.0f, 0.0f};
     87     
     88     // GL_TRIANGLES 每3个顶点定义一个新的三角形
     89     triangleBatch.Begin(GL_TRIANGLES, 12);
     90     triangleBatch.CopyVertexData3f(vPyramid);
     91     triangleBatch.End();
     92     
     93 
     94     // 6、圆环  三角形条带,一个小环或圆柱段
     95     // 顶点下标
     96     int iCounter = 0;
     97     // 半径
     98     GLfloat radius = 3.0f;
     99     //从0度~360度,以0.3弧度为步长
    100     for(GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f) {
    101         //或许圆形的顶点的X,Y
    102         GLfloat x = radius * sin(angle);
    103         GLfloat y = radius * cos(angle);
    104         
    105         //绘制2个三角形(他们的x,y顶点一样,只是z点不一样)
    106         vPoints[iCounter][0] = x;
    107         vPoints[iCounter][1] = y;
    108         vPoints[iCounter][2] = -0.5;
    109         iCounter++;
    110         
    111         vPoints[iCounter][0] = x;
    112         vPoints[iCounter][1] = y;
    113         vPoints[iCounter][2] = 0.5;
    114         iCounter++;
    115     }
    116     // 关闭循环
    117     printf("三角形带的顶点数:%d
    ",iCounter);
    118     // 结束循环,在循环位置生成2个三角形
    119     vPoints[iCounter][0] = vPoints[0][0];
    120     vPoints[iCounter][1] = vPoints[0][1];
    121     vPoints[iCounter][2] = -0.5;
    122     iCounter++;
    123     
    124     vPoints[iCounter][0] = vPoints[1][0];
    125     vPoints[iCounter][1] = vPoints[1][1];
    126     vPoints[iCounter][2] = 0.5;
    127     iCounter++;
    128     
    129     // GL_TRIANGLE_STRIP 共用一个条带(strip)上的顶点的一组三角形
    130     triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
    131     triangleStripBatch.CopyVertexData3f(vPoints);
    132     triangleStripBatch.End();
    133 
    134 
    135     // 7、三角形扇形 -- 六边形
    136     GLfloat vPoints[100][3];    
    137     int nVerts = 0;
    138     // 半径
    139     GLfloat r = 3.0f;
    140     // 原点(x,y,z) = (0,0,0);
    141     vPoints[nVerts][0] = 0.0f;
    142     vPoints[nVerts][1] = 0.0f;
    143     vPoints[nVerts][2] = 0.0f;
    144     
    145     // M3D_2PI 就是2Pi 的意思,就一个圆的意思。 绘制圆形
    146     for(GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
    147         
    148         // 数组下标自增(每自增1次就表示一个顶点)
    149         nVerts++;
    150         /*
    151          弧长=半径*角度,这里的角度是弧度制,不是平时的角度制
    152          既然知道了cos值,那么角度=arccos,求一个反三角函数就行了
    153          */
    154         // x点坐标 cos(angle) * 半径
    155         vPoints[nVerts][0] = float(cos(angle)) * r;
    156         // y点坐标 sin(angle) * 半径
    157         vPoints[nVerts][1] = float(sin(angle)) * r;
    158         // z点的坐标
    159         vPoints[nVerts][2] = -0.5f;
    160     }
    161     
    162     // 结束扇形 前面一共绘制7个顶点(包括圆心)
    163     // 添加闭合的终点
    164     nVerts++;
    165     vPoints[nVerts][0] = r;
    166     vPoints[nVerts][1] = 0;
    167     vPoints[nVerts][2] = 0.0f;
    168     
    169     // 加载
    170     // GL_TRIANGLE_FAN 以一个圆心为中心呈扇形排列,共用相邻顶点的一组三角形
    171     triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);// 8个顶点?7的话扇形是无法闭合的
    172     triangleFanBatch.CopyVertexData3f(vPoints);
    173     triangleFanBatch.End();
    174 }

    绘制:void RenderScene();

    下图,我们是看不出立体效果的

    设置偏移:

      glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要绘制填充和边线,会产生z-Flighting 冲突,所以要偏移

      glEnable(GL_POLYGON_OFFSET_LINE);

    开启颜色混合:

      glEnable(GL_BLEND);

      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

     1 void DrawWireFramedBatch(GLBatch* pBatch) {
     2 
     3     /*------------画绿色部分----------------*/
     4     /* GLShaderManager 中的Uniform 值 —— 平面着色器
     5      参数1:平面着色器
     6      参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
     7           --transformPipeline 变换管线(指定了2个矩阵堆栈)
     8      参数3:颜色值
     9     */
    10     shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
    11     pBatch->Draw();// 第 1 次绘制
    12     
    13     /*-----------边框部分-------------------*/
    14     /*
    15         glEnable(GLenum mode); 用于启用各种功能。功能由参数决定
    16         参数列表:https://www.cnblogs.com/zhangying-domy/p/13276529.html
    17         注意:glEnable() 不能写在glBegin() 和 glEnd()中间
    18         GL_POLYGON_OFFSET_LINE  根据函数glPolygonOffset的设置,启用线的深度偏移
    19         GL_LINE_SMOOTH          执行后,过虑线点的锯齿
    20         GL_BLEND                启用颜色混合。例如实现半透明效果
    21         GL_DEPTH_TEST           启用深度测试 根据坐标的远近自动隐藏被遮住的图形(材料
    22      
    23         glDisable(GLenum mode); 用于关闭指定的功能 功能由参数决定
    24      */
    25     // 设置偏移  画黑色边框
    26     glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
    27     glEnable(GL_POLYGON_OFFSET_LINE);
    28     
    29     // 画反锯齿,使平滑 让黑边好看些
    30     glEnable(GL_LINE_SMOOTH);
    31     
    32     // 颜色混合
    33     glEnable(GL_BLEND);
    34     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    35     
    36     //绘制线框几何黑色版 三种模式,实心,边框,点,可以作用在正面,背面,或者两面
    37     //通过调用glPolygonMode将多边形正面或者背面设为线框模式,实现线框渲染
    38     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);// 线的形式填充
    39     //设置线条宽度
    40     glLineWidth(2.5f);
    41     
    42     /* GLShaderManager 中的Uniform 值 —— 平面着色器
    43      参数1:平面着色器
    44      参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
    45          --transformPipeline.GetModelViewProjectionMatrix() 获取的
    46           GetMatrix函数就可以获得矩阵堆栈顶部的值
    47      参数3:颜色值(黑色)
    48      */
    49     shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    50     pBatch->Draw();// 第 2 次绘制
    51 
    52     // 恢复初始状态 复原原本的设置
    53     // 通过调用glPolygonMode将多边形正面或者背面设为全部填充模式
    54     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    55     glDisable(GL_POLYGON_OFFSET_LINE);
    56     glLineWidth(1.0f);
    57     glDisable(GL_BLEND);
    58     glDisable(GL_LINE_SMOOTH);
    59 }

    Demo链接 

    三、矩阵堆栈

    // 类型
    GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
    // 在堆栈顶部载⼊一个单元矩阵
    void GLMatrixStack::LoadIdentity(void);
    // 在堆栈顶部载⼊任何矩阵 
    // 参数:4*4矩阵
    void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
    // 矩阵 乘以 矩阵堆栈顶部矩阵,相乘结果存储到堆栈的顶部
    void GLMatrixStack::MultMatrix(const M3DMatrix44f);
    // 获取矩阵堆栈顶部的值 GetMatrix 函数 
    // 为了适应GLShaderMananger的使用,或者获取顶部矩阵的副本
    const M3DMatrix44f & GLMatrixStack::GetMatrix(void);
    void GLMatrixStack::GetMatrix(M3DMatrix44f mMatrix);
    
    // 将当前矩阵压⼊堆栈 (栈顶矩阵copy 一份到栈顶) 
    void GLMatrixStack::PushMatrix(void);
    // 将M3DMatrix44f 矩阵对象压⼊当前矩阵堆栈
    void PushMatrix(const M3DMatrix44f mMatrix);
    // 将GLFame 对象压⼊矩阵对象
    void PushMatrix(GLFame &frame);
    // 出栈(移除顶部的矩阵对象) 
    void GLMatrixStack::PopMatrix(void);

    矩阵压栈的过程(图片来自:简书凡几多):

  • 相关阅读:
    Vue's Demo
    安装informatic过程中的错误
    linux系统字符集
    netstat
    查看linux系统的信息
    以太坊私有链的搭建
    $0 $1
    WordPaster-Joomla_3.4.7-tinymce 4.1.7示例发布
    Joomla3x-CKEditor4x-WordPaster整合示例
    Firefox 43无法安装xpi的问题
  • 原文地址:https://www.cnblogs.com/zhangzhang-y/p/13298426.html
Copyright © 2020-2023  润新知