OpenGL学习笔记(5)----坐标系统、摄像机
引言
上一次笔记学习了OpenGL中的着色器的基本操作,纹理的使用,以及变换矩阵,我已经可以绘制出一个有纹理,会移动的2D三角形了。经过这一次的学习,我能够通过实现坐标系统将一个3D空间中的3D立方体绘制到屏幕空间中,还可以自定义摄像机类,在3D空间中自由移动。
坐标系统
先讲一些理论的东西。
理论
将坐标变换为标准化设备坐标,接着再转化为屏幕坐标的过程通常是分步进行的,也就是类似于流水线那样子。在流水线中,物体的顶点在最终转化为屏幕坐标之前还会被变换到多个坐标系统(Coordinate System)。目前比较重要的坐标系统有:
- 局部空间(Local Space,或者称为物体空间(Object Space))
- 世界空间(World Space)
- 观察空间(View Space,或者称为视觉空间(Eye Space))
- 裁剪空间(Clip Space)
- 屏幕空间(Screen Space)
在这些空间之间转换的过程中中有3个重要的矩阵:模型(model),观察(view),投影(projection)矩阵。
这一系列的空间中的坐标初始为vec4,即三个位置坐标和一个齐次坐标。
局部空间
局部空间中的坐标为局部坐标,位置坐标是模型的导入时的坐标,齐次坐标一般设为1.0。局部空间的原点由建模人员在建模时决定的,一般在物体中心。
世界空间
世界空间就是整个3D世界的空间,该空间中的坐标称为世界坐标。
模型坐标需要变换操作(缩放,旋转,平移)变为世界坐标,这个变换操作通过模型矩阵实现,模型矩阵是模型相关的。
观察空间
观察空间也叫摄像机空间(Camera Space)或者视觉空间(Eye Space),该阶段坐标称为观察坐标。
从世界空间到观察空间的过程是把物体相对于世界原点的坐标转化为相对于摄像机的坐标,具体做法就是把摄像机相对于世界原点的位移、旋转操作反向加到所有物体的世界坐标上,这个操作就是观察矩阵做的事。观察矩阵是摄像机相关的。
裁剪空间
在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个特定的范围内,且任何在这个范围之外的点都应该被裁剪掉(Clipped)。被裁剪掉的坐标就会被忽略,所以剩下的坐标就将变为屏幕上可见的片段。这也就是裁剪空间(Clip Space)名字的由来。
从观察空间到裁剪空间就是完成下面两个空间的映射(透视投影时)
该映射需要两个过程,先将观察坐标通过投影矩阵转化成裁剪坐标,再通过透视除法将剪裁坐标变成标准化设备坐标(normalized device coordinates NDC)。如下图所示
裁剪坐标是为了方便计算定义出来的坐标。
投影矩阵
从观察坐标转到裁剪坐标需要投影矩阵来操作,投影矩阵有两个主要的参数,投影方式和摄像机的观察箱(一个平截头体Frustum)。投影矩阵是摄像机相关的。
投影方式
投影方式有两种:
- 正射投影
正射平截头体直接将平截头体内部的所有坐标映射为标准化设备坐标,齐次坐标不改变。 - 透视投影
透视投影将给定的平截头体范围映射到裁剪空间,除此之外还修改了每个顶点坐标的w值(齐次坐标),从而使得离观察者越远的顶点坐标w分量越大。(投影矩阵的具体数学方法)
透视除法
当透视投影时,矩阵乘出的坐标是裁剪坐标,OpenGL会自动进行一个叫做透视除法的操作,将裁剪坐标变成标准化设备坐标:
o u t = ( x / w y / w z / w ) out = \begin{pmatrix} x /w \\ y / w \\ z / w \end{pmatrix} out=⎝⎛x/wy/wz/w⎠⎞
这个操作会使更远处坐标的绝对值变小,形成下面的效果:
当正射投影时,矩阵乘出的坐标直接是标准化设备坐标,不进行透视除法。
屏幕空间
将标准化设备坐标变换为屏幕坐标,OpenGL会使用一个叫做视口变换(Viewport Transform)的过程。视口变换将位于-1.0到1.0范围的裁剪坐标变换到由glViewport函数所定义的坐标范围内。最后变换出来的坐标将会送到光栅器,将其转化为片段。
代码实现
在上面几个空间的转换中,我们需要向顶点着色器提供三个矩阵model,view,projection。其中model矩阵是模型相关,一个模型对应一个model矩阵;view,projection矩阵是摄像机相关。
坐标转换的公式:
V c l i p = M p r o j e c t i o n ⋅ M v i e w ⋅ M m o d e l ⋅ V l o c a l V_{clip} = M_{projection} \cdot M_{view} \cdot M_{model} \cdot V_{local} Vclip=Mprojection⋅Mview⋅Mmodel⋅Vlocal
在得到Vclip后,OpenGL会自动对顶点坐标进行透视除法和视口转换。
model矩阵
该矩阵可以用上一节的知识自己定义模型的位置、大小、旋转。
glm::mat4 model = glm::mat4(