上篇博客(OpenGL专有名词解析)讲到了物体变换位置有一种方法通过坐标系变化,但由于OpenGL中坐标系统不是简短几句话能描述的,因此我们专门开篇梳理一下OpenGL的坐标系统。
要详细了解OpenGL中多重坐标系, 首先我们需要了解从我们开发者构造的坐标系(Local/Object Space)转换到屏幕上坐标系 (Screen Coordinates)显示的具体过程。
上图描绘了物体从局部对象坐标系统到屏幕坐标系转换的详细流程, 列举一下OpenGL中的坐标系。
- World Coordinates(世界坐标系)
- Object Coordinates(对象坐标系、模型坐标系、局部坐标系或当前绘图坐标系)
- Eye Coordinates(眼坐标系或照相机坐标系)
- Clip Coordinates(裁剪坐标系)
- Normalized Device Coordinates (NDC) (归一化设备坐标系)
- Window Coordinates (Screen Coordinates)(屏幕坐标)
在OpenGL中,这个转变过程可以看做下图
OpenGL中Model和View一般用做一个模型视图变换矩阵ModelViewMatrix来处理。
下面我们通过矩阵的演变过程来看下计算流程:
[Tips]以上变换流程中, 哪些是开发者需要做的,哪些是OpenGL会自动处理的呢?
- 顶点计算过程中(参考上图)模型变换、视变换,投影变换,这些变换可以由用户根据需要自行指定,这些内容在顶点着色器中完成;
- 透视除法、视口变换,这两个步骤是OpenGL自动执行的,在顶点着色器处理后的阶段完成。
流程详解:
1. 从模型坐标系(局部/对象坐标系 Object Coordinates)到世界坐标系(World Coordinates)
模型坐标系主要用于设计模型,在此阶段我们无需关心最终对象显示在屏幕哪个位置(因为决定显示在哪还需要加上摄像机来决定)。
在OpenGL中缓存对象(buffer object)中保存,以及旧版本中使用的glVertex3f等函数指定的都是局部坐标系中的坐标。
所谓从模型坐标系转换到世界坐标系,也就是将物体局部坐标转换到世界坐标系下坐标。
模型变换包括平移(translation)、旋转(rotation)、缩放(scaling)等等。
简单来说,这个过程主要做的事情就是我们在做仿射变化时通过调用modelViewMatrix的translation,Rotate,Scale等方法,将物体变化记录到模型视图矩阵当中。当然,如果不进行变化, 那就是默认情况。
在固定功能绘制管线下,默认情况下OpenGL里model-view 和projection矩阵都是单位阵。如果没有应用任何变换,对象坐标系和世界坐标系是相同的。同时默认情形下,对象坐标系、照相机坐标系和裁剪坐标系3个坐标系是重合的。
默认情况下,OpenGL执行正交投影;照相机位于世界坐标系原点,照相机指向-Z轴方向,照相机正向为+Y轴方向。
2.从世界坐标系(World Coordinates)到照相机坐标系(Eye Coordinates)
- 首先:为什么要将世界坐标转换到照相机坐标系呢?
自己总结一个观点。因为最终的成像要通过照相机模型来进行(不添加是为默认情况,参考上述),我们将世界坐标系中位置转换到照相机坐标系来进行,能够简化物体移动的实现。实际上这个转换可以理解为,从照相机/人眼看到的世界坐标系中场景是什么样子。 - 我们要形成的一个观点就是: 场景不动时,移动照相机等价于照相机不动,以逆变换的形式变换场景。 这种变换在OpenGL中比在第一个过程中通过模型视图矩阵变换要简单许多, 例如
//MoveForward 平移
cameraFrame.MoveForward(0.1f);
//RotateWorld 旋转
cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
3.从照相机坐标系(Eye Coordinates)到裁剪坐标系(Clip Coordinates)
相机坐标系到裁剪坐标系是通过投影完成的。
OpenGL中我们使用视景体GLFrustum来创建投影矩阵,设置投影方式。
投影就是将物体投影到投影平面的过程。因为OpenGL使用的是虚拟相机成像模型,因此也使用了正交投影和透视投影两种方式。
实际上,投影有很多种类,这里稍微整理下常见的平行投影(正投影)和透视投影。
平行投影的投影线相互平行,投影的结果与原物体的大小相等,因此广泛地应用于工程制图等方面。正交投影是平行投影的一种特殊情形,正交投影的投影线垂直于观察平面。物体不会因为远近而缩小。
透视投影的投影线相交于一点,因此投影的结果与原物体的实际大小并不一致,而是会近大远小。因此透视投影更接近于真实世界的投影方式。
[Tips]因为人眼的特殊生理性,一般二维图形我们采用正投影,三维使用透视投影。
4.从裁剪坐标系(Clip Coordinates)到规范化设备坐标系(NDC)
这个过程就是透视除法的过程,在OpenGL中无须我们自己处理。它会在顶点着色器处理后的阶段完成。
5.从规范化设备坐标系(NDC)到屏幕坐标系(Window Coordinates)
这个过程也就是视口变换,我们在glViewport指定后OpenGL自动处理。同过程4, 也是在顶点着色器处理后的阶段完成。
视口变换——从NDC到屏幕坐标
视变换是将规范化设备坐标(NDC)转换为屏幕坐标的过程,如下图所示:
视口变化通过函数:
glViewport(GLint sxsx , GLint sysy , GLsizei wsws , GLsizei hshs);
glDepthRangef(GLclampf nsns , GLclampf fsfs );
两个函数来指定。其中(sxsx,sysy)表示窗口的左下角,nsns和 fsfs指定远近剪裁平面到屏幕坐标的映射关系。视口变换矩阵的推导可以参考前面的投影矩阵和视口变换矩阵一节。用上面的glViewport和glDepthRangef函数指定参数后,视口变换由OpenGL自动执行,不需要额外代码。
参考文章: