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

OpenGL中图形绘制后,往往需要一系列的变换来达到用户的目的,而这种变换实现的原理是又通过矩阵进行操作的。opengl中的变换一般包括视图变换、模型变换、投影变换等,在每次变换后,opengl将会呈现一种新的状态(这也就是我们为什么会成其为状态机)。有时候在经过一些变换后我们想回到原来的状态,就像我们谈恋爱一样,换来换去还是感觉初恋好,怎么办?强大的openg…

大家好,又见面了,我是你们的朋友全栈君。

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

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

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

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

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

    OpenGL的glPushMatrix和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 "include\glut.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 }

    运行结果:

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

 

转载于:https://www.cnblogs.com/1024Planet/p/5650162.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/127308.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mysql和redis的区别

    mysql和redis的区别1.mysql和redis的数据库类型mysql是关系型数据库,主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。redis是NOSQL,即非关系型数据库,也是缓存数据库,即将数据存储在缓存中,缓存的读取速度快,能够大大的提高运行效率,但是保存时间有限2.mysql的运行机制mysql作为持久化存储的关系型数据库,相对薄弱的地方在于每次请求访问数据库时,都存在着I/O操作,如果反复…

    2022年6月14日
    38
  • matlab int8 矩阵,unit8_matlab数据类型转换——int8转换成unit8「建议收藏」

    matlab int8 矩阵,unit8_matlab数据类型转换——int8转换成unit8「建议收藏」在一个驱动程序中看到uint16,uint32,unit8,int8…uint16:无符号16bit整数,uint32:无符号32bit整数,unit8:无符号8bit整数,int8:有符号8bit整数。其作用是程序更加简洁,增强可移植性和可维护性,尤其是在16位机器,32位,或者是64位机器上相互之间移植的时候只需要修改这些宏定义就可以满足要求了,而不需要去修改整个工程里边的每一个变量定义…

    2022年9月17日
    0
  • Python一.Python安装及环境配置(完整教程)「建议收藏」

    Python一.Python安装及环境配置(完整教程)「建议收藏」Windowns操作系统中安装Python一.下载Python1.python官网:https://www.python.org/downloads/下载安装包2.选择版本我这里用安装版(64位)二.双击安装1.这里勾选安装并添加到PAHT,下一步。一直默认就可以安装完成2、查看环境变量是否有python的环境变量在命令窗口输入python-V回车如果出现python版本,那么恭喜…

    2022年5月31日
    32
  • Java线程池详解「建议收藏」

    Java线程池详解「建议收藏」文章目录简介什么是线程池银行营业厅案例执行流程创建方式所有创建方式通过ThreadPoolExecutor创建简介什么是线程池线程池(ThreadPool)是一种基于池化思想管理和使用线程的机制。它是将多个线程预先存储在一个“池子”内,当有任务出现时可以避免重新创建和销毁线程所带来性能开销,只需要从“池子”内取出相应的线程执行对应的任务即可。常见的运用池化思想的有:内存池、数据库连接池。使用线程的优点如下:提高线程的利用率提高程序的相应速度便于统一管理线程对象银行营业厅案例假设银行正常可

    2022年7月9日
    20
  • android之database disk image is malformed (code 11)

    做来电显示归属地和查询归属地功能的时候,需要从服务器下载数据库,但是下载之后,查询总是报错database disk image is malformed (code 11)开始以为是查询语句不对,后来意识到,跟之前解析包时出现错误是一样的问题,下载过程中格式损坏了。于是解决方法跟http://blog.csdn.net/jason0539/article/details/2174

    2022年3月11日
    40
  • DIV ID用途_纸的用途

    DIV ID用途_纸的用途我是超级链接这个例子是一个很简单的超级链接。用到了DIV,实际上DIV就相当于一个肉眼看不到盒子,盒子里边可以放入很多的文字、图片、flash等等。而盒子里边内容的样式,就全部靠DIV的id所对应的

    2022年8月1日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号