原文https://52zju.cn/?p=575
定点坐标(对象坐标系)→ MModelView → 眼坐标系 → MProjection → 裁剪坐标系 → w分离 → 标准化设备坐标系 → 视口转换 → 窗口坐标系
从坐标的角度来看,过程如下:
在实际当中,不存在单独的model,view transformation,而是将这两次变换组合成一个模式变换model-view transform来进行。
实际上,OpenGL只定义了裁剪坐标系,规范化设备坐标系和屏幕坐标系。而局部坐标系世界坐标系和照相机坐标系都是为了方便用户设计而自定义的坐标系。
默认情况下,OpenGL里的model-view和projection矩阵都是单位矩阵。如果没有应用任何变换,对象坐标系和世界坐标系都是相同的。同时默认情况下,对象坐标系,照相机坐标系和裁剪坐标系3个坐标系是重合的。
默认情况下,OpenGL执行正交投影,照相机位于世界坐标系原点,照相机指向-Z轴方向,照相机方向为+Y轴方向。
对象的本地坐标,可以说是用户坐标系(UCS)而非世界坐标系。其中几何变换操作(transformation)如:glRotate(),glTranslatef(),glScalef(),就是在此坐标系上进行的。
对象坐标系主要是用于设计模型,在此阶段我们无需关系最终对象显示在屏幕哪个位置。如下图几个图形的局部坐标系如下:
世界坐标系始终是固定不变的。OpenGL使用右手坐标,这里有一个形象的方法:使用右手定则
X 是你的拇指
Y 是你的食指
Z 是你的中指
如果你把你的拇指指向右边,食指指向天空,那么中指将指向你的背后。我们的观察方向是Z轴负半轴的方向。
进行旋转操作时需要指定的角度θ的方向则由右手法则来决定,即右手握拳,大拇指直向某个坐标轴的正方向,那么其余四指指向的方向即为该坐标轴上的θ角的正方向(即θ角增加的方向),图中用圆弧形箭头标出。
所谓从对象坐标系转换到世界坐标系,也就是将物体局部坐标转换到世界坐标系下的坐标。例如下图的3个茶壶都是在自己的局部坐标系来定义:通过对3个茶壶实施模型变换,将他们转换到世界坐标系下如下图所示:
模型变换包括平移translation,旋转rotation,缩放scaling等等。
眼坐标系也可以称为相机坐标系。就是用谁来观看的问题。
模型变换:对象坐标系->世界坐标系
视变换:世界坐标系->眼坐标系
为啥要转换到眼坐标系呢?可以这样理解,通过前面的MODEVIEW变换,这个世界坐标系中的场景已经绘制好了。这时候我们还不能看到场景,因为我们的观察位置还没确定,而且如果我们眼睛(照相机)的位置不同,那么观察物体的角度则不同,那看到的场景的样子肯定也不同,所以要有这一步,把场景与我们的观察位置对应起来。
实际上,照相机指向的位置,观察正方向(VUP)都是在世界坐标系下指定的,如下图所示:
从名字上看裁剪坐标系应该定义了物体在投影平面上可视部分。由视觉坐标系和GL_PROJECTION矩阵相乘得到: [xcli ycli zcli]T = MProjection • [xeye yeye zeye]T
具体见上一篇博客:三维重建: 裁剪空间以及透视变换的理解
由裁剪坐标系下通过除以W分量得到。这个操作称为透视除法。NDC坐标很像屏幕坐标,但是还没有经过平移和缩放到屏幕像素。现在3个轴上的值范围均为[-1,1]。
也叫屏幕坐标系,原点在左上角——auxInitPosition就是初始化一个窗口
另外还有一个概念:视口(Viewport),即在窗口中用于显示图像的那部分——glViewport定义了视口
通过NDC缩小和平移(以便适应屏幕的透视)得到
对于glViewPort(x,y,w,h);和glDepthRange(n,f);
[xw yw zw]T = [(w / 2 * xndc + x + w /2) (h / 2 * yndc + y + h /2) ((f – n) / 2 * zndc + (f + n) / 2)]T
这里其实就是一个单纯的线性映射关系
-1 → x; 1 → x + w
-1 → y; 1 → y + h
-1 → n; 1 → f
参考链接:
https://www.jianshu.com/p/9b110a5ba424
http://www.360doc.com/content/14/1028/09/19175681_420513219.shtml
http://www.codinglabs.net/article_world_view_projection_matrix.aspx