一: 摄像机
- OpenGL本身没有摄像机(Camera)的概念,但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生一种我们在移动的感觉,而不是场景在移动。
- 以摄像机的视角作为场景原点时场景中所有的顶点坐标:观察矩阵把所有的世界坐标变换为相对于摄像机位置与方向的观察坐标。
- 要定义一个摄像机,我们需要它在世界空间中的位置、观察的方向、一个指向它右测的向量以及一个指向它上方的向量。
- 实际上创建了一个三个单位轴相互垂直的、以摄像机的位置为原点的坐标系。
- 摄像机位置:摄像机位置简单来说就是世界空间中一个指向摄像机位置的向量。
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
-
摄像机方向:这里指的是摄像机指向哪个方向。现在我们让摄像机指向场景原点:(0, 0, 0)。
2.1 用场景原点向量减去摄像机位置向量的结果就是摄像机的指向向量。
2.2 由于我们知道摄像机指向z轴负方向,但我们希望方向向量(Direction Vector)指向摄像机的z轴正方向。如果我们交换相减的顺序,我们就会获得一个指向摄像机正z轴方向的向量:glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f);//表示摄像机指向的地方,即原点 glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);//方向向量,与指向的方向相反的向量
2.3 ** 方向向量 **:(与实际指向的方向相反)方向向量(Direction Vector)并不是最好的名字,因为它实际上指向从它到目标向量的相反方向(注意看前面的那个图,蓝色的方向向量大概指向z轴的正方向,与摄像机实际指向的方向是正好相反的)。 - 右轴:需要的另一个向量是一个右向量(Right Vector),它代表摄像机空间的x轴的正方向。为获取右向量我们需要先使用一个小技巧:先定义一个上向量(Up Vector)。接下来把上向量和第二步得到的方向向量进行叉乘。两个向量叉乘的结果会同时垂直于两向量,因此我们会得到指向x轴正方向的那个向量(如果我们交换两个向量叉乘的顺序就会得到相反的指向x轴负方向的向量):
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f); glm::vec3 cameraRight = glm::normalize(glm::cross(up, cameraDirection));
- 上轴:已经有了x轴向量(cameraRight)和z轴向量(cameraDirection),获取一个指向摄像机的正y轴向量就相对简单了:我们把右向量和方向向量进行叉乘:
glm::vec3 cameraUp = glm::cross(cameraDirection, cameraRight);
二:LookAt矩阵
- 使用矩阵的好处之一是如果你使用3个相互垂直(或非线性)的轴定义了一个坐标空间,你可以用这3个轴外加一个平移向量来创建一个矩阵,并且你可以用这个矩阵乘以任何向量来将其变换到那个坐标空间。
- 有了3个相互垂直的轴和一个定义摄像机空间的位置坐标,可以创建自己的LookAt矩阵
- LookAt矩阵就像它的名字表达的那样:它会创建一个看着(Look at)给定目标的观察矩阵。
- 位置向量在矩阵中运算时时相反的:因为我们最终希望把世界平移到与我们自身移动的相反方向。
- glm::LookAt函数需要一个位置、目标和上向量。它会创建一个和在上一节使用的一样的观察矩阵。(根据以上的分析,有了这三个向量足以构建出LookAt矩阵)
glm::mat4 view;
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), //摄像机的位置向量
glm::vec3(0.0f, 0.0f, 0.0f), //目标位置向量
glm::vec3(0.0f, 1.0f, 0.0f));//上向量
三: 视角移动
- 为了能够改变视角,我们需要根据鼠标的输入改变cameraFront向量(上面说的方向向量:cameraDirection)。
- 欧拉角:俯仰角(Pitch)、偏航角(Yaw)和滚转角(Roll)
2.1 俯仰角(Pitch):如何往上或往下看的角,绕x轴
2.2 偏航角(Yaw):偏航角表示我们往左和往右看的程度,绕y轴
2.3 滚转角(Roll):如何翻滚摄像机,绕z轴