摄像机实现的原理:通过位移 旋转对原物体的坐标反向变换,模拟相机机位的变化,详细推演可以参考《计算机视觉基础》第6章-几何变换 p105和第13章节-交互式图形流程。核心公式:
从右往左看,第一个矩阵调整原始点的位移,模拟相机的反向位移,第二个矩阵模拟坐标的旋转。没有理解原理硬记下也是可以的。
一、实现一个基础的摄像机环绕效果
- 效果
- opengl中的实现:幸运的是,GLM已经提供了这些支持。我们要做的只是定义一个摄像机位置,一个目标位置和一个表示世界空间中的上向量的向量(我们计算右向量使用的那个上向量)。 接着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));
- 代码和上一篇中区别很小,对view的实现做了调整,代码如下:
float radius = 10.0f;
float camX = sin(glfwGetTime()) * radius;
float camZ = cos(glfwGetTime()) * radius;
view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
方便观察,把每个立方体自旋转部分的逻辑注释掉了
代码语言:javascript复制 for (unsigned int i = 0; i < 10; i ) {
glm::mat4 model;
model = glm::translate(model, cubePositions[i]);
// float angle = 20.0f * i (float)glfwGetTime();
// model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f));
ourShader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
二、按键调整相机机位
1.效果
按键调整
2.代码说明,有两处需要修改 // main函数里的变量提出来,方便在processInput里全局引用
代码语言:javascript复制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);
// 在processInput中监听按键,W S A D分别控制上下左右移动,跟打CS游戏一样,注意,左右移动机位需要归一化,目的是控制移动速度平稳,因为初始值在操作过程中是个变值。
代码语言:javascript复制void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){
glfwSetWindowShouldClose(window, true);
}
float cameraSpeed = 0.05f;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
cameraPos = cameraSpeed * cameraFront;
} else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
cameraPos -= cameraSpeed * cameraFront;
} else if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
} else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
cameraPos = glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}
}
// while循环中view的计算
代码语言:javascript复制view = glm::lookAt(cameraPos, cameraPos cameraFront, cameraUp);
代码语言:javascript复制注意!!view = glm::lookAt(cameraPos, cameraPos cameraFront, cameraUp);一开始对cameraPos cameraFront怎么也不理解,既然是表示方向,方向向量的标量值是没有意义的,很奇怪,做了个实验,写死glm::lookAt第二个参数看效果,发现第二个值如果和第一个值一样大,屏幕空白,只要第二个值比第一个参数小,哪怕只小一点点效果就正常。仔细看了glm::lookAt方法的说明,第二个参数并不是向量,是一个三维坐标,即相机拍摄的方向,如果这个点和相机镜头是同一个点,那该往哪个方向看呢?系统自己就傻了。
view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.0f, 2.9f), cameraUp);