OpenGL笔记之矩阵变换(Matrix Transformation)
本文是学习OpenGL过程中的一篇笔记。在学习过程中,主要参照了大名鼎鼎的
- 《OpenGL Programming Guide》(中文名《OpenGL编程指南》,有些人还称之为OpenGL红宝书)《OpenGL SuperBible》(中文名《OpenGL超级宝典》,有些人还称之为OpenGL蓝宝书)
另外还有
《3D Computer Graphics: A Mathematical Introduction with OpenGL》《Advanced Graphics Programming Using OpenGL Morgan Kaufmann Series in Computer Graphics and Geometric Modeling 》《3D Math Primer for graphics and game development》等书籍。


1,应用程序传送给OpenGL的顶点位置坐标,法线向量坐标、纹理坐标以及光源坐标都是定义在对象坐标系中的。如果应用程序开启了基于对象坐标系的纹理生成,那么这些纹理坐标的生成是利用末经模型视图矩阵变换的顶点位置坐标生成的,所以这种情况下如果移动或者旋转物体,纹理将和物体一起移动或者旋转,实例请参考蓝宝书第9章的TEXGEN程序。
2,模型转换(Modeling Transformation):使用模型转换的目的是设置物体在场景中的位置(position)和方向(orientation)。通常,为了正确的在场景中放置每个物体,每个物体都需要一个不同的模型转换。如果要使物体产生运动效果,也需要在每帧更新时对物体使用不同的模型转换。
3,视觉转换(Viewing Transformation):使用视觉转换的目的是改变场景中所有物体的位置和方向,换句话说,就是改变观察的位置和方向。
4,使用glLight命令给定光源位置和方向时,在光源位置和方向被OpenGL存储之前会经过模型视图矩阵(ModelView Matrix)的变换。如果没有用glLight命令更新的话,这些位置和方向将一直被OpenGL在计算光照时使用。
5,在视觉坐标系中,物体光照效果发生作用,基于视觉坐标系的纹理坐标生成也是发生在视觉坐标系中的。默认情况下,视点(或者说成照相机)位于视觉坐标系原点,指向Z轴负方向,向上向量为(0,1,0),请参见下图。

由于视觉坐标系指向Z轴负方向,所以glFrustum(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far)和gluPerspective(GLdouble fovy,GLdoubleaspect,GLdoublenear, GLdoublefar)中的near和far是在以Z轴负方向的情况下指定的。
可以直接使用gluLookAt来改变视点的位置和方向。注意,在OpenGL代码中,视觉转换一定要发生在模型转换之前,可以在绘图之前的任何时刻进行投影变换和视口变换。
如果使能光照的话,openGL会在视觉坐标系中使用视点位置,光源位置和法线向量来进行光照计算,从而修改物体顶点的颜色。为了便于理解,这里引用一个光照模型图,如下:

6,投影变换(Project Transformation):投影变换的一个显著特征是透视缩短,即物体如果离照相机的距离越远,则它看上去就越小。透视投影可以看成一个金字塔的平截头体。靠近观察点的物体看上去会更大一些,因为和远处的物体相比,他们占据了视景体中相对较大的区域。

投影变换其实是对对象进行变形处理,使得变形后的对象经正交投影后得到与原对象的理想投影后一样的视图(详细请参见:投影矩阵)。
透视投影在图形学中非常重要,因为它是人类视觉系统的模型。为便于理解,我们以小孔成像来说明它的基本原理。请参见下图:

图中右边的茶壶经过小孔投影到左边的立方体中。其剖面图如下:

为了计算上的方便,我们将投影平面移到投影的前面,如下图:

这就是OpenGL使用的投影原理。
我们可以用glFrustum建立投影视景体,如下图:

此时,投影后所形成的最终图像将会显示在near平面上。投影矩阵的推导过程请参见《OpenGL Projection Matrix》。
7,透视除法(Perspective Division):通过透视除法,我们可以得到NDC(Normalized Device Coordinate)。规范化的原因是不想为每种类型的投影设计不同的投影矩阵,所以把所有的投影转换为具有默认视景体的正交投影。
通过投影变换和透视除法,我们得到NDC。这个过程可能难于理解,下面我们用计算机图形学中的一点透视来解释一下(详细请参见《三
设:视点(投影中心)在Z轴上(z=-d),投影面在XOY上,一点透视的步骤:
①平移三维形体到(l、m、n)
②确定d的值,透视变换
③向XOY作正投影变换


8,窗口变换矩阵(Viewport Transformation):在NDC视景体中的每一个点(x,y,z),其x,y,z取值范围都在区间[-1,1]内。它的x和y坐标映射到一个以(Vx,Vy)为起点,宽为w,高为h,中心点为(Vx+w/2, Vy+y/2)的窗口(Viewport)中。z坐标默认映射到范围[0,1]中,也可改变它,使它映射到[Dn,Df]中,这样深度范围d=Df-Dn,并且它的中心点是(Dn+Df)/2。这样,实现从NDC到窗口坐标转换的窗口变换矩阵是:

下面是2张效果示例图:


9,关于红宝书中3.2节视图和模型转换中提到的局部移动坐标系可以参考《3D Math Primer for graphics and game development》3.5节Coordinate Space Transformations进行理解。