三、矩阵的压栈和出栈原理分析
这里引入两个重要的操作 : 矩阵的 压栈 和 出栈 , 这是 OpenGL 固定管线中的重要操作 ;
显卡栈 : 矩阵在显卡中有一个栈 , 该显卡中的栈可以存储 n nn 个矩阵 ;
栈顶矩阵 : 栈顶的矩阵是 模型视图 ( ModelView ) 矩阵 , 该矩阵的值是 单位阵 E \rm EE ( 主对角线元素是 1 11 , 其它位置都是 0 00 ) ;
矩阵压栈 : 调用 GLPushMatrix 方法进行压栈时 , 会将栈顶的矩阵拷贝一份 , 然后放在栈顶 , 原来的模型视图矩阵 , 就处于栈顶的下方位置 , 即栈内的第二个元素 ;
矩阵压栈后 , 所有的对于矩阵的操作都是针对栈顶的 矩阵 进行的操作 , 该栈顶矩阵是 模型视图矩阵 的一份拷贝 ;
矩阵出栈 : 调用 方法进行出栈操作 , 就将已经修改过的 模型视图矩阵 的拷贝弹出栈 , 恢复成原始的 模型视图矩阵 , 此时的模型视图矩阵就是原本的矩阵 , 不再需要在渲染开始的位置 , 设置单位阵了 ;
矩阵的 压栈 出栈 可以嵌套多层 , 用于绘制复杂的联动模型 ;
嵌套两层的 压栈 出栈 操作 :
第一次压栈 : 将 E \rm EE 拷贝一份 , A \rm AA 矩阵 , 放在栈顶 , 对 A \rm AA 矩阵进行一系列操作 ;
第二次压栈 : 将 A \rm AA 矩阵拷贝一份 , B \rm BB 矩阵 , 放在栈顶 , 对 B \rm BB 矩阵进行一系列操作 ;
第一次出栈 : 将 B \rm BB 矩阵弹出 , 即从栈顶移出 , 恢复成 A \rm AA 矩阵 ;
第二次出栈 : 将 A \rm AA 矩阵弹出栈 , 恢复成单位阵 E \rm EE ;
四、矩阵的压栈和出栈代码示例
矩阵的压栈和出栈代码示例 :
// 只显示正面 , 不显示背面 //glEnable(GL_CULL_FACE); // 设置顺时针方向 CW : Clock Wind 顺时针方向 // 默认是 GL_CCW : Counter Clock Wind 逆时针方向 //glFrontFace(GL_CW); // 默认模式, 填充模式 , 如果不设置就默认为填充模式 //glPolygonMode(GL_FRONT, GL_FILL); // 设置线框模式 // 设置了该模式后 , 之后的所有图形都会变成线 //glPolygonMode(GL_FRONT, GL_LINE); // 设置点模式 // 设置了该模式后 , 之后的所有图形都会变成点 //glPolygonMode(GL_FRONT, GL_POINT); // 将方形的点变为圆点 //glEnable(GL_POINT_SMOOTH); //glEnable(GL_BLEND); // 主消息循环: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } // 渲染场景 // 设置单位矩阵 //glLoadIdentity(); // 矩阵压栈 glPushMatrix(); // 矩阵缩放 // 缩放的是下面设置的点的坐标 // 每个参数都影响 x , y , z 分量 //glScalef(2.0f, 2.0f, 1.0f); // 平移变换 // 设置 xyz 三个方向平移的值 glTranslatef(0.0f, -2.0f, 0.0f); // 矩阵旋转 // glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); // 第 1 个参数是旋转角度 , 后面三个参数的值代表是否绕该轴旋转 , // 如果对应值设置为 1 , 则绕该轴旋转 // 这里设置的是绕 z 轴旋转 30 度 glRotatef(30.0f, 0.0f, 0.0f, 1.0f); // 清除缓冲区 , // 使用之前设置的 glClearColor(1.0, 0.0, 0.0, 1.0) 擦除颜色缓冲区 // 红色背景 glClear(GL_COLOR_BUFFER_BIT); // 设置当前的绘制颜色 , 4 个 unsigned byte // 每个颜色的分量占一个字节 // 参数数据是 R 红色 G 绿色 B 蓝色 A 透明度 // 下面设置的含义是白色, 绘制点的时候, 每次都使用白色绘制 glColor4ub(255, 255, 255, 255); // 设置当前点的大小 glPointSize(5.0f); // 设置线的宽度 glLineWidth(5.0f); //glBegin(GL_POINTS); // 绘制点 //glBegin(GL_LINES); // 绘制线 //glBegin(GL_LINE_STRIP);// 绘制前后连接的点组成的线 //glBegin(GL_LINE_LOOP); // 绘制前后连接的点组成的线 , 并且收尾相连 //glBegin(GL_TRIANGLES); // 绘制多个三角形 //glBegin(GL_TRIANGLE_STRIP); // 绘制 GL_TRIANGLE_STRIP 三角形 //glBegin(GL_TRIANGLE_FAN); // 绘制三角形扇 // 绘制三角形 glBegin(GL_TRIANGLES); // 1. 设置白色 , glVertex3f (GLfloat x, GLfloat y, GLfloat z) glColor4ub(255, 255, 255, 255); glVertex3f(0.0f, 1.0f, -5.0f); // 2. 设置绿色 glColor4ub(0, 255, 0, 255); glVertex3f(-1.0f, 0.0f, -5.0f); // 3. 设置蓝色 glColor4ub(0, 0, 255, 255); glVertex3f(1.0f, 0.0f, -5.0f); // 绘制三角形结束 glEnd(); // 矩阵出栈 glPopMatrix(); // 将后缓冲区绘制到前台 SwapBuffers(dc); }
最终效果 :
五、相关资源
GitHub 地址 : https://github.com/han1202012/OpenGL
( GitHub 源码始终都会随着后续博客的进度更新覆盖 , 可能没有本博客的相关源码 , 推荐下载博客源码快照 ) ;
博客源码快照 : https://download.csdn.net/download/han1202012/14901367
( 该源码是 Windows 桌面程序 , 使用 Visual Studio 2019 打开 )