在OpenGL中从上方移动相机

Posted

技术标签:

【中文标题】在OpenGL中从上方移动相机【英文标题】:Moving camera from above in OpenGL 【发布时间】:2021-09-16 17:18:35 【问题描述】:

我正在使用来自https://learnopengl.com/Getting-started/Camera 的Camera 类(您可以找到代码here)。

我想让相机看向 y 轴的负方向(从上方)。

但是,简单地将默认音高更改为 -90 并相应地更改它的约束值并不能解决问题。它改变了相机的方向,但它的运动完全被破坏了。

我想我需要更改updateCameraVectors() 中的数学;有人可以帮帮我吗?

#pragma once
//camera class from learnopengl.com

#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include <vector>

// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum Camera_Movement 
    FORWARD,
    BACKWARD,
    LEFT,
    RIGHT
;

// Default camera values
const float YAW = -90.0f;
const float PITCH = -90.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.1f;
const float ZOOM = 45.0f;


// An abstract camera class that processes input and calculates the corresponding Euler Angles, Vectors and Matrices for use in OpenGL
class Camera

public:
    // Camera Attributes
    glm::vec3 Position;
    glm::vec3 Front;
    glm::vec3 Up;
    glm::vec3 Right;
    glm::vec3 WorldUp;
    // Euler Angles
    float Yaw;
    float Pitch;
    // Camera options
    float MovementSpeed;
    float MouseSensitivity;
    float Zoom;

    // Constructor with vectors
    Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
    
        Position = position;
        WorldUp = up;
        Yaw = yaw;
        Pitch = pitch;
        updateCameraVectors();
    
    // Constructor with scalar values
    Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
    
        Position = glm::vec3(posX, posY, posZ);
        WorldUp = glm::vec3(upX, upY, upZ);
        Yaw = yaw;
        Pitch = pitch;
        updateCameraVectors();
    

    // Returns the view matrix calculated using Euler Angles and the LookAt Matrix
    glm::mat4 GetViewMatrix()
    
        return glm::lookAt(Position, Position + Front, Up);
    

    // Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
    void ProcessKeyboard(Camera_Movement direction, float deltaTime)
    
        float velocity = MovementSpeed * deltaTime;
        if (direction == FORWARD)
            Position += Front * velocity;
        if (direction == BACKWARD)
            Position -= Front * velocity;
        if (direction == LEFT)
            Position -= Right * velocity;
        if (direction == RIGHT)
            Position += Right * velocity;
    

    // Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
    void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true)
    
        xoffset *= MouseSensitivity;
        yoffset *= MouseSensitivity;

        Yaw += xoffset;
        Pitch += yoffset;

        // Make sure that when pitch is out of bounds, screen doesn't get flipped
        if (constrainPitch)
        
            if (Pitch > -1.0f)
                Pitch = -1.0f;
            if (Pitch < -179.0f)
                Pitch = -179.0f;
        

        // Update Front, Right and Up Vectors using the updated Euler angles
        updateCameraVectors();
    

    // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
    void ProcessMouseScroll(float yoffset)
    
        if (Zoom >= 1.0f && Zoom <= 45.0f)
            Zoom -= yoffset;
        if (Zoom <= 1.0f)
            Zoom = 1.0f;
        if (Zoom >= 90.0f)
            Zoom = 90.0f;
    

private:
    // Calculates the front vector from the Camera's (updated) Euler Angles
    void updateCameraVectors()
    
        // Calculate the new Front vector
        glm::vec3 front;
        front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
        front.y = sin(glm::radians(Pitch));
        front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
        Front = glm::normalize(front);
        // Also re-calculate the Right and Up vector
        Right = glm::normalize(glm::cross(Front, WorldUp));  // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
        Up = glm::normalize(glm::cross(Right, Front));
    
;

【问题讨论】:

【参考方案1】:
Right = glm::normalize(glm::cross(Front, WorldUp));
Up = glm::normalize(glm::cross(Right, Front));

这是一种非常“懒惰”的方式来确定右向量和上向量。它做了一堆假设,包括一个你永远不会直视或直视的假设。

想一想:如果我们通过将“前进”与世界上的“向上”概念进行比较来计算“右”是什么,那么当“前进”指向直上或直下时,“右”应该是什么?

一个更简洁的方法是:

    从 Pitch 和 Yaw 创建一个变换矩阵 将该矩阵应用于所有三个参考轴。 (可选)使用叉积重新正交化生成的三个向量。

【讨论】:

您能详细说明一下这些步骤吗?

以上是关于在OpenGL中从上方移动相机的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL - 让相机移动

需要帮助在 OpenGL 中移动相机

相机直接到 iOS 上的 OpenGL 纹理

OpenGL模拟波斯王子相机

OpenGL:移动相机时如何使光线静止?

c++ opengl 相机移动