opengl入门-摄像机

2020-06-15 11:09:13 浏览数 (2)

摄像机实现的原理:通过位移 旋转对原物体的坐标反向变换,模拟相机机位的变化,详细推演可以参考《计算机视觉基础》第6章-几何变换 p105和第13章节-交互式图形流程。核心公式:

从右往左看,第一个矩阵调整原始点的位移,模拟相机的反向位移,第二个矩阵模拟坐标的旋转。没有理解原理硬记下也是可以的。

一、实现一个基础的摄像机环绕效果
  1. 效果
  1. opengl中的实现:幸运的是,GLM已经提供了这些支持。我们要做的只是定义一个摄像机位置,一个目标位置和一个表示世界空间中的上向量的向量(我们计算右向量使用的那个上向量)。 接着GLM就会创建一个LookAt矩阵,我们可以把它当作我们的观察矩阵:
代码语言:javascript复制
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));
  1. 代码和上一篇中区别很小,对view的实现做了调整,代码如下:
代码语言:javascript复制
        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);

注意!!view = glm::lookAt(cameraPos, cameraPos cameraFront, cameraUp);一开始对cameraPos cameraFront怎么也不理解,既然是表示方向,方向向量的标量值是没有意义的,很奇怪,做了个实验,写死glm::lookAt第二个参数看效果,发现第二个值如果和第一个值一样大,屏幕空白,只要第二个值比第一个参数小,哪怕只小一点点效果就正常。仔细看了glm::lookAt方法的说明,第二个参数并不是向量,是一个三维坐标,即相机拍摄的方向,如果这个点和相机镜头是同一个点,那该往哪个方向看呢?系统自己就傻了。

代码语言:javascript复制
view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.0f, 2.9f), cameraUp);

0 人点赞