一、模型空间
模型空间也叫做对象空间,假设我们有一个杯子,该杯子我们就可以看作是一个模型空间,杯子的中心点为坐标(0,0,0)。
一般来说我们想将杯子显示在屏幕上,首先我们应该将杯子转换到世界空间下(世界空间也有对应的顶点以及坐标系)。那么我们应该如何来做到这一步呢?我们可以判断,模式坐标系是如何从世界坐标系变换得到的。此处就要涉及局部坐标系相对于世界坐标系的位置和方向,或者说空间中的点的位置发生变化时,坐标如何变化。
考虑三种基本的变换:平移、旋转和缩放。
OpenGL对模型进行旋转、平移和缩放。用到三个子函数: glTranslate*(x, y, z) 、 glRotate*(x, y, z) 、 glScale*(x, y, z) 。每个函数都会产生一个矩阵,并右乘当前矩阵。
对于一个点p我们要对它平移、旋转、缩放得到p'。
可由p'=glScale*(x, y, z)*glRotate*(x, y, z)*glTranslate*(x, y, z) *p
得到的变换矩阵为:
Model Matrix = glScale*(x, y, z)**glRotate*(x, y, z)*glTranslate*(x, y, z)
通过对应Model Matrix变换,我们得到了杯子各个点在世界坐标系下的坐标。
因此我们知道了一个点,模型空间的作用就是,将目标物体的坐标从模型坐标系转换到世界坐标系中。
二、视图矩阵
视图矩阵是对于观察者来说的,例如:
如果将观察者视为一个模型,那么视图矩阵就是观察者的模型矩阵的逆矩阵。
观察者平移了(tx, ty, tz),相当于整个世界平移了(-tx, -ty, -tz)。
观察者绕Z轴旋转了角度θ,相当于整个世界绕Z轴旋转了-θ度。
观察者在三个方向等比例缩小了s倍,相当于整个世界等比例放大了s倍。
所以说当观察者的位置发生了变换以后,看上去就好像整个世界的位置和方向发生了改变。
我们以平移为例:
把摄像机向 右 (X轴正方向)移动3个单位,这和把整个世界(包括网格)向 左 (X轴负方向)移3个单位是等效的。
glm::mat4 ViewMatrix = glm::translate(-3.0f, 0.0f, 0.0f);
使用了GLM(OpenGL Mathematics)库,一个用于OpenGL的C++数学库,主要作用是创建一个视图矩阵(ViewMatrix)。将整个世界向x轴负方向移动了3个点位。
通过视图矩阵(ViewMatrix),我们将目标物体的坐标从世界坐标系下,转化到了视图坐标系下。
对于视图矩阵的求解,我们可以通过上面所说矩阵的逆运算求解,还可以使用OpenGL中的函数,如gluLookAt:通过给定视点、观察点以及up向量,可以直接求得视图矩阵。
glm::mat4 CameraMatrix = glm::LookAt(
cameraPosition, // 相机的位置,在世界坐标系中
cameraTarget, // 相机的目标点,即你希望相机看向的点,在世界坐标系中
upVector // 相机的上方向向量,通常是glm::vec3(0, 1, 0),但也可以是其他值,比如 //glm::vec3(0, -1, 0)会使相机头朝下
);
观察者的位置和方向会变化,看上去就好像整个世界的位置和方向发生变化了一样,所以我们将世界里的所有模型看作一个大模型,在所有模型矩阵的左侧再乘以一个表示整个世界变换的模型矩阵,就可以了。这个表示整个世界变换的矩阵又称为视图矩阵,因为他们经常一起工作,所以将视图矩阵乘以模型矩阵,用它乘以一个点的坐标,获得的新坐标表示:点相对于观察者的位置。
三、投影矩阵
投影矩阵是我们自己设定的,与我们使用的相机与屏幕有关,通过下面这个函数
glm::mat4 projectionMatrix = glm::perspective(
FoV, // 水平视场(Field of View),以度为单位:表示“缩放”量。可以想象成“相机镜头”。通常介于90°(超广角)和30°(相当缩放)之间
4.0f / 3.0f, // 纵横比。取决于你的窗口大小。注意,4/3 == 800/600 == 1280/960
0.1f, // 近裁剪面。尽可能大,否则你会遇到精度问题。
100.0f // 远裁剪面。尽可能小。
);
我们就得到了投影矩阵projectionMatrix
最后,根据投影矩阵×视图矩阵×模型矩阵求出模型视图投影矩阵,顶点坐标乘以该矩阵就直接获得其在规范立方体中的坐标了。