函数原型:

void glMatrixMode(GLenum mode)

参数说明:

mode 指定哪一个矩阵堆栈是下一个矩阵操作的目标,可选值: 

  •   GL_MODELVIEW,对模型视图矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,输出自己的物体图形了。
  •   GL_PROJECTION,对投影矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,为我们的场景增加透视。
  •   GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,为我们的图形增加纹理贴图。

在每个矩阵模式下都有一个矩阵堆栈,在GL_MODELVIEW模式中,堆栈深度至少为32;在GL_PROJECTION和GL_TEXTURE模式中,堆栈深度至少为2;在任何模式中,当前矩阵总是该模式下矩阵堆栈中的最顶层矩阵。

函数说明:

glMatrixMode()命令将当前矩阵设置成参数所指定的模式,以满足不同绘图所需执行的矩阵变换。一般而言,在需要绘制出对象或要对所绘制对象进行几何变换时,需要将变换矩阵设置成模型视图模式;而当需要对绘制的对象设置某种投影方式时,则需要将变换矩阵设置成投影模式;只有在进行纹理映射时,才需要将变换矩阵设置成纹理模式。

与glLoadIdentity()一同使用,glLoadIdentity()功能是重置当前指定的矩阵为单位矩阵。

我们生活在一个三维的世界——如果要观察一个物体,我们可以:
1、从不同的位置去观察它。(视图变换)
2、移动或者旋转它,当然了,如果它只是计算机里面的物体,我们还可以放大或缩小它。(模型变换)
3、如果把物体画下来,我们可以选择:是否需要一种“近大远小”的透视效果。另外,我们可能只希望看到物体的一部分,而不是全部(剪裁)。(投影变换)
4、我们可能希望把整个看到的图形画下来,但它只占据纸张的一部分,而不是全部。(视口变换)
这些,都可以在OpenGL中实现。

OpenGL变换实际上是通过矩阵乘法来实现。无论是移动、旋转还是缩放大小,都是通过在当前矩阵的基础上乘以一个新的矩阵来达到目的。OpenGL可以在最底层直接操作矩阵,不过作为初学,这样做的意义并不大。这里就不做介绍了。

一、模型变换和视图变换
       从“相对移动”的观点来看,改变观察点的位置与方向和改变物体本身的位置与方向具有等效性。在OpenGL中,实现这两种功能甚至使用的是同样的函数。

由于模型和视图的变换都通过矩阵运算来实现,在进行变换前,应先设置当前操作的矩阵为“模型视图矩阵”。设置的方法是以GL_MODELVIEW为参数调用glMatrixMode函数,像这样:

glMatrixMode(GL_MODELVIEW); //需要修改的是模型视图矩阵、投影矩阵还是纹理矩阵。mode的值可以为:GL_MODELVIEW、GL_PROJECTION或GL_TEXTURE。

通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。这也只需要一行代码:

glLoadIdentity();

然后,就可以进行模型变换和视图变换了。进行模型和视图变换,主要涉及到三个函数:

  1. glTranslate*:把当前矩阵和一个表示移动物体的矩阵相乘。三个参数分别表示了在三个坐标上的位移值。
  2. glRotate*:把当前矩阵和一个表示旋转物体的矩阵相乘。物体将绕着(0,0,0)到(x,y,z)的直线以逆时针旋转,参数angle表示旋转的角度。
  3. glScale*:把当前矩阵和一个表示缩放物体的矩阵相乘。x,y,z分别表示在该方向上的缩放比例。

注意我都是说“与XX相乘”,而不是直接说“这个函数就是旋转”或者“这个函数就是移动”,这是有原因的,马上就会讲到。
       假设当前矩阵为单位矩阵,然后先乘以一个表示旋转的矩阵R,再乘以一个表示移动的矩阵T,最后得到的矩阵再乘上每一个顶点的坐标矩阵v。所以,经过变换得到的顶点坐标就是((RT)v)。由于矩阵乘法的结合率,((RT)v) = (R(Tv)),换句话说,实际上是先进行移动,然后进行旋转。即:实际变换的顺序与代码中写的顺序是相反的。由于“先移动后旋转”和“先旋转后移动”得到的结果很可能不同,初学的时候需要特别注意这一点。
       OpenGL之所以这样设计,是为了得到更高的效率。但在绘制复杂的三维图形时,如果每次都去考虑如何把变换倒过来,也是很痛苦的事情。这里介绍另一种思路,可以让代码看起来更自然(写出的代码其实完全一样,只是考虑问题时用的方法不同了)。
       让我们想象,坐标并不是固定不变的。旋转的时候,坐标系统随着物体旋转。移动的时候,坐标系统随着物体移动。如此一来,就不需要考虑代码的顺序反转的问题了。

以上都是针对改变物体的位置和方向来介绍的。如果要改变观察点的位置,除了配合使用glRotate*和glTranslate*函数以外,还可以使用这个函数:gluLookAt。它的参数比较多,前三个参数表示了观察点的位置,中间三个参数表示了观察目标的位置,最后三个参数代表从(0,0,0)到 (x,y,z)的直线,它表示了观察者认为的“上”方向。

二、投影变换
       投影变换就是定义一个可视空间,可视空间以外的物体不会被绘制到屏幕上。(注意,从现在起,坐标可以不再是-1.0到1.0了!)
       OpenGL支持两种类型的投影变换,即透视投影和正交投影。投影也是使用矩阵来实现的。如果需要操作投影矩阵,需要以GL_PROJECTION为参数调用glMatrixMode函数。

glMatrixMode(GL_PROJECTION);

通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。

glLoadIdentity();

透视投影所产生的结果类似于照片,有近大远小的效果,比如在火车头内向前照一个铁轨的照片,两条铁轨似乎在远处相交了。
1.使用glFrustum函数可以将当前的可视空间设置为透视投影空间。其参数的意义如下图:

       这个函数原型为:

void glFrustum(GLdouble left, GLdouble Right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);

创建一个透视型的视景体。其操作是创建一个透视投影的矩阵,并且用这个矩阵乘以当前矩阵。这个函数的参数只定义近裁剪平面的左下角点和右上角点的三维空间坐标,即(left,bottom,-near)和(right,top,-near);最后一个参数far是远裁剪平面的离视点的距离值,其左下角点和右上角点空间坐标由函数根据透视投影原理自动生成。near和far表示离视点的远近,它们总为正值(near/far 必须>0)。

  1. void mydisplay (void)
  2. {
  3. ......
  4. glMatrixMode (GL_PROJECTION);
  5. LoadIdentity ();
  6. Frustum (left, right, bottom, top, near, far);
  7. ......
  8. }

2.也可以使用更常用的gluPerspective函数

这个函数原型为:

void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear, GLdouble zFar);

  创建一个对称的透视型视景体,但它的参数定义于前面的不同,如图。其操作是创建一个对称的透视投影矩阵,并且用这个矩阵乘以当前矩阵。参数fovy定义视野在Y-Z平面的角度,范围是[0.0, 180.0];参数aspect是投影平面宽度与高度的比率;参数Near和Far分别是近远裁剪面到视点(沿Z负轴)的距离,它们总为正值。
  以上两个函数缺省时,视点都在原点,视线沿Z轴指向负方向。
3.正交投影相当于在无限远处观察得到的结果,它只是一种理想状态。但对于计算机来说,使用正交投影有可能获得更好的运行速度。
       使用glOrtho函数可以将当前的可视空间设置为正投影空间,如下图所示:

       这个函数的原型为:

void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far) 

六个参数,前两个是x轴最小坐标和最大坐标,中间两个是y轴,最后两个是z轴值。它创建一个平行视景体(就是一个长方体空间区域)。实际上这个函数的操作是创建一个正射投影矩阵,并且用这个矩阵乘以当前矩阵。其中近裁剪平面是一个矩形,矩形左下角点三维空间坐标是(left,bottom,-near),右上角点是(right,top,-near);远裁剪平面也是一个矩形,左下角点空间坐标是(left,bottom,-far),右上角点是(right,top,-far)。
       注意,所有的near和far值同时为正或同时为负,值不能相同。如果没有其他变换,正射投影的方向平行于Z轴,且视点朝向Z负轴。这意味着物体在视点前面时far和near都为负值,物体在视点后面时far和near都为正值。

只有在视景体里的物体才能显示出来。如果最后两个值是(0,0),也就是near和far值相同了,视景体深度没有了,整个视景体都被压成个平面了,就会显示不正确。

三、视口变换
       当一切工作已经就绪,只需要把像素绘制到屏幕上了。这时候还剩最后一个问题:应该把像素绘制到窗口的哪个区域呢?通常情况下,默认是完整的填充整个窗口,但我们完全可以只填充一半。(即:把整个图象填充到一半的窗口内)
运用相机模拟方式,我们很容易理解视口变换就是类似于照片的放大与缩小。在计算机图形学中,它的定义是将经过几何变换、投影变换和裁剪变换后的物体显示于屏幕窗口内指定的区域内,这个区域通常为矩形,称为视口。
       在实际中,视口的长宽比率总是等于视景体裁剪面的长宽比率。如果两个比率不相等,那么投影后的图像显示于视口内时会发生变形,如图所示。

 
       使用glViewport来定义视口。其中前两个参数定义了视口的左下脚(0,0表示最左下方),后两个参数分别是宽度和高度。

void glViewport(GLint x,GLint y,GLsizei width,GLsizei height);

四、操作矩阵堆栈
         介于是入门教程,先简单介绍一下堆栈。你可以把堆栈想象成一叠盘子。开始的时候一个盘子也没有,你可以一个一个往上放,也可以一个一个取下来。每次取下的,都是最后一次被放上去的盘子。通常,在计算机实现堆栈时,堆栈的容量是有限的,如果盘子过多,就会出错。当然,如果没有盘子了,再要求取一个盘子,也会出错。
        我们在进行矩阵操作时,有可能需要先保存某个矩阵,过一段时间再恢复它。当我们需要保存时,调用glPushMatrix函数,它相当于把矩阵(相当于盘子)放到堆栈上。当需要恢复最近一次的保存时,调用glPopMatrix函数,它相当于把矩阵从堆栈上取下。OpenGL规定堆栈的容量至少可以容纳32个矩阵,某些OpenGL实现中,堆栈的容量实际上超过了32个。因此不必过于担心矩阵的容量问题。通常,用这种先保存后恢复的措施,比先变换再逆变换要更方便,更快速。

注意:模型视图矩阵和投影矩阵都有相应的堆栈。使用glMatrixMode来指定当前操作的究竟是模型视图矩阵还是投影矩阵。

参考链接:https://blog.csdn.net/timidsmile/article/details/7016755

OpenGL之glMatrixMode函数的用法相关推荐

  1. OpenGl的glMatrixMode()函数理解

    https://blog.csdn.net/jiangdf/article/details/8460012 glMatrixMode()函数的参数,这个函数其实就是对接下来要做什么进行一下声明,也就是 ...

  2. OpenGL之glViewPort函数的用法

    其函数原型为:glViewport(GLint x,GLint y,GLsizei width,GLsizei height) x,y 以像素为单位,指定了视口的左下角位置. width,height ...

  3. OpenGL:glMatrixMode()

    在OpenGL中,如果想对模型进行操作,就要对这个模型的状态(当前的矩阵)乘上这个操作对应的一个矩阵. 如果当前矩阵乘以变换矩阵(平移, 缩放, 旋转), 那相乘之后, 模型的位置被变换; 如果当前矩 ...

  4. OpenGL中glRotatef()函数究竟对矩阵做了什么

    OpenGL中glRotatef()函数究竟对矩阵做了什么 我们知道OpenGL中维持着两套矩阵,一个是模型视图矩阵(model view matrix),另一个是投影矩阵(projection ma ...

  5. python map用法_Python中 map()函数的用法详解

    python map()函数问题 使用map()函数生成一个值D但是检测D的长度时,只能测一次,一次之后D似不知道你的dataSet 是什么数据,是否是从数据库取出来的结果游标, 如果是的 那么dat ...

  6. OpenGL的API函数使用手册

    OpenGL的API函数使用手册 (一)OpenGL函数库 格式: <库前缀><根命令><可选的参数个数><可选的参数类型> 库前缀有 gl.glu.a ...

  7. OpenGL中glMatrixMode的使用,以及glPushMatrix和glPopMatrix的原理

    一.glMatrixMode()函数的参数,这个函数其实就是对接下来要做什么进行一下声明,也就是在要做下一步之前告诉计算机我要对"什么"进行操作了,这个"什么" ...

  8. 关于C语言中的malloc和free函数的用法

    一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...

  9. Python assert断言函数及用法

    Python assert断言函数及用法 Python assert 语句,又称断言语句,可以看做是功能缩小版的 if 语句,它用于判断某个表达式的值,如果值为真,则程序可以继续往下执行:反之,Pyt ...

最新文章

  1. Zabbix监控MongoDB
  2. CentOS7配置iptables防火墙
  3. 思维导图下载 注册安全_2019安全工程师《建筑实务》第二章第一节考点:物料提升机思维导图...
  4. java 注解 属性 类型_跟光磊学Java开发-Java注解
  5. Linux服务器安装cuda,cudnn,显卡驱动和pytorch超详细流程
  6. Qt杂记-QQuick之Android隐藏状态栏以及状态栏透明(QQuick项目)
  7. centos yum安装php5.5,奇妙伞-Centos下使用yum安装PHP5.5,5.6,7.0
  8. Node.js中使用pipe拷贝大文件不能完全拷贝的解决办法
  9. 简单的 Nodejs jade 实现Hello world
  10. 笔记本计算机涂硅脂,笔记本cpu怎么更换散热硅脂?笔记本电脑cpu涂硅脂教程
  11. 电脑桌面的计算机网络回收站图标不见了,桌面回收站图标不见了怎么办 回收站图标找回方法【图文】...
  12. 微信公众平台之模拟登录
  13. 相机标定与三维重建原理
  14. 常见的WebShell管理工具
  15. ThinkPHP 5.0 rewrite规则
  16. 京东MySQL数据库Docker化最佳实践(附PPT)
  17. python控制台小游戏_学习编程的好方法——控制台游戏
  18. 【Android视频号③ Xposed插件编写】
  19. VS2008下载(包含中文MSDN)序列号 破解版【深海收藏】
  20. 化工行业的配方保密管理

热门文章

  1. fastjson将json字符串转为Map对象,拿走不谢
  2. 使用apply调用函数
  3. rmReport 自适应行高(自动行高)
  4. Eclipse java项目转换为web项目
  5. 查看进程-查看端口占用-杀进程
  6. 在网上找了一些j2ee的视频教程,有需要的朋友可以看看
  7. Laravel增加自定义助手函数
  8. 五个计算机软件,近五个交易日计算机软件概念股市复盘(4月19日)
  9. 设计模式复习-解释器模式
  10. Win64 驱动内核编程-30.枚举与删除线程回调