• OpenGL的glPushMatrix和glPopMatrix矩阵栈顶操作函数详解


            OpenGL中图形绘制后,往往需要一系列的变换来达到用户的目的,而这种变换实现的原理是又通过矩阵进行操作的。opengl中的变换一般包括视图变换、模型变换、投影变换等,在每次变换后,opengl将会呈现一种新的状态(这也就是我们为什么会成其为状态机)。

            有时候在经过一些变换后我们想回到原来的状态,就像我们谈恋爱一样,换来换去还是感觉初恋好,怎么办?强大的opengl就帮我们提供了两个函数:giPushMatrix()和glPopMatrix();

            首先我们要知道,对于矩阵的操作都是对于矩阵栈的栈顶来操作的。当前矩阵即为矩阵栈的栈顶元素,而对当前矩阵进行平移、旋转等的变换操作也同样是对栈顶矩阵的修改。所以我们在变换之前调用giPushMatrix()的话,就会把当前状态压入第二层,不过此时栈顶的矩阵也与第二层的相同。

           当经过一系列的变换后,栈顶矩阵被修改,此时调用glPopMatrix()时,栈顶矩阵被弹出,且又会恢复为原来的状态。

           函数的作用过程可以用下图描述,更为直观。

        

              在opengl场景中一般存在多种矩阵变换操作,而控制这些操作的命令主要用到

              glMatrixMode(GLenum mode); 
              作用:用于指定用哪个矩阵作为当前矩阵,mode用于指定哪一种矩阵栈是其后矩阵操作的目标。mode可取: 
               GL_MODELVIEW: 把其后的矩阵操作施加于造型视图矩阵栈。(默认) 
               GL_PROJECTION: 把其后的矩阵操作施加于投影矩阵栈。 
               GL_TEXTURE: 把其后的矩阵操作施加于纹理矩阵栈。

              注意上述三种模式分别对应了三种矩阵栈。

              所以在场景中存在多种矩阵变换时,glPushMatrix()和glPopMatrix()一般情况下也要结合glMatrixMode(GLenum mode)运用,系统才知道具体操作的是哪个矩阵栈。

              注意:

              摄像机矩阵和模型矩阵用的是同一个矩阵,就是GL_MODELVIEW (model是模型搜索矩阵,view是摄像机矩阵,GL_MODELVIEW里保存的是这两个矩阵的积)。所以选择GL_MODELVIEW之后直接用glTranslate,glRotate之类的就行。

              其实摄像机和模型矩阵本质上是一回事(这也是为什么OpenGL把这两个矩阵放在一起保存的原因),因为比如把整个世界向y+方向移动10跟把摄像机向y-方向移动10是等价的。旋转也是一样。

              虽然矩阵里可以保存任何变换,但按照OpenGL的概念,model和view矩阵里只能保存平移,旋转和缩放;project矩阵里只能保存投影矩阵,viewport矩阵里只能保存二维平移和缩放。这样来看把model和view放在一起是合理的。他们之间的区别纯粹是人为的。

        附上代码例子:

     1 #include <stdlib.h>
     2 #include "includeglut.h"
     3 
     4 static int year = 0, day = 0;
     5 
     6 void init(void)
     7 {
     8     glClearColor (0.0, 0.0, 0.0, 0.0);
     9     glShadeModel (GL_FLAT);
    10 }
    11 
    12 void display(void)
    13 {
    14     glClear (GL_COLOR_BUFFER_BIT);
    15     glColor3f (1.0, 1.0, 1.0);
    16     
    17     glPushMatrix();
    18     {
    19         glutWireSphere(1.0, 20, 16); /* draw sun */
    20         glRotatef ((GLfloat) year, 0.0, 1.0, 0.0);
    21 
    22         glTranslatef (2.0, 0.0, 0.0);    //把坐标原点变换位置
    23 
    24         glRotatef ((GLfloat) day, 0.0, 1.0, 0.0);
    25         glutWireSphere(0.2, 10, 8); /* draw smaller planet */
    26     }
    27     glPopMatrix();
    28 
    29     glutSwapBuffers();
    30 }
    31 
    32 void reshape(int w, int h)
    33 {
    34     glViewport (0, 0, (GLsizei) w, (GLsizei) h);
    35     glMatrixMode (GL_PROJECTION);
    36     glLoadIdentity ();
    37     gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
    38 
    39     glMatrixMode(GL_MODELVIEW);
    40     glLoadIdentity();
    41     gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    42 }
    43 
    44 void keyboard(unsigned char key, int x, int y)
    45 {
    46     switch (key) {
    47         case 'd':
    48             day = (day + 10) % 360;
    49             glutPostRedisplay();
    50             break;
    51         case 'D':
    52             day = (day - 10) % 360;
    53             glutPostRedisplay();
    54             break;
    55         case 'y':
    56             year = (year + 5) % 360;
    57             glutPostRedisplay();
    58             break;
    59         case 'Y':
    60             year = (year - 5) % 360;
    61             glutPostRedisplay();
    62             break;
    63         case 27:
    64             exit(0);
    65             break;
    66         default:
    67             break;
    68     }
    69 }
    70 
    71 int main(int argc, char** argv)
    72 {
    73     glutInit(&argc, argv);
    74     glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
    75     glutInitWindowSize (500, 500);
    76     glutInitWindowPosition (100, 100);
    77     glutCreateWindow (argv[0]);
    78     
    79     init();
    80     glutDisplayFunc(display);
    81     glutReshapeFunc(reshape);
    82     glutKeyboardFunc(keyboard);
    83     glutMainLoop();
    84     return 0;
    85 }

        运行结果:

        

  • 相关阅读:
    iOS的生命周期
    【iOS开发】在 App 中加入 AdMob 广告
    iOS性能优化:Instruments
    动态的计算行高 加载数据源 有多少显示多少 tableView 包含 colloctionView 显示复杂的界面写法
    Java String.split()注意点
    Java eclipse export jar包 包括第三方引入的jar
    微信网页授权获取用户基本信息
    android连接本地tomcat服务器,报timeout
    iOS内存管理retain,assign,copy,strong,weak
    static与全局与局部变量的区别
  • 原文地址:https://www.cnblogs.com/1024Planet/p/5650162.html
Copyright © 2020-2023  润新知