1.前序:
OpenGL中本来是没有摄像机的概念,但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生出一种物体在移动的感觉,而不是场景在移动。
在本章节中,我们将学习如何通过键盘输入,让物体能够在3D场景中自由移动。
我们所谓的摄像机,其实就是观察空间,实质上就是以摄像机的角度作为场景原点时,场景中所有的顶点坐标:观察矩阵把所有的世界坐标变换为相对于摄像机位置与方向的观察坐标。要定义一个摄像机,我们需要它在世界空间中的位置、观察的方向、一个指向它右侧的向量,以及指向它上方的向量。指向右侧和指向上方的向量是为了方便我们对他进行移动。
2.获取摄像机位置
摄像机位置简单来说就是世界空间中一个指向摄像机的向量。我们把摄像机位置设置为上一节中的那个相同的位子。
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
这里我们需要注意的是,正Z轴是从屏幕指向我们自己的,如果我们希望摄像机往后移,我们就沿着Z轴的正方向移动。
glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);
3.摄像机方向
我们有了摄像机初始位置过后,我们还需要的向量就是摄像机移动的方向,这里指的是摄像机指向哪个方向,我们现在将摄像机指向场景原点。
glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f);
由于我们知道摄像机指向z轴负方向,但我们希望方向向量指向摄像机的z轴正方向。如果我们交换相减的顺序,我们就会获得一个指向摄像机正z轴方向的向量:
4.右轴
我们需要的另一个向量就是右向量。它代表着摄像机空间的x轴正方向。为了得到右向量,我们可以先定义一个上向量。接下来我们把上向量和第二步得到的方向向量进行叉乘。两个向量叉乘的结果会同时垂直于两向量,然后我们就能得到指向x轴的正方向向量。
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 cameraRight = glm::normalize(glm::cross(up, cameraDirection));
5.上轴
我们已经得到了x轴和z轴的向量,获取y轴就变得很简单了,我们只需要把又向量和方向向量进行叉乘,我们就能得到y轴向量。
glm::vec3 cameraUp = glm::cross(cameraDirection, cameraRight);
6.LookAt
我们有了三个互相垂直的轴和一个定义摄像机空间的位置坐标,我们就可以创建LookAt矩阵了。LookAt矩阵会将所有与它相乘的向量变换到那个坐标空间。
glm提供了lookAt这个技术,我们要做的只是定义一个摄像机位置,一个目标位置和一个表示世界空间的上向量的向量。接着glm就会创建一个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));
我们可以试着让我们的摄像机在在场景中旋转起来
float radius = 10.0f;
float camX = sin(glfwGetTime()) * radius;
float camZ = cos(glfwGetTime()) * radius;
glm::mat4 view; view = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
7.自由移动
首先我们必须设置一个摄像机系统。
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
接着我们将LookAt函数改为:
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
最后我们就添加几个需要检查的按键命令
void processInput(GLFWwindow *window) {
float cameraSpeed = 0.05f; // adjust accordingly
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
cameraPos += cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
cameraPos -= cameraSpeed * cameraFront;
if(glfwGetKey(window,GLFW_KEY_A)== GLFW_PRESS)
cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
if (glfwGetKey(window,GLFW_KEY_D)==GLFW_PRESS)
cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}
然后我们就可以通过键盘上的WSAD控制摄像机移动了!!!