使用 glm 的飞行相机表现得很奇怪

Flying camera using glm is acting weird

我正在开发一个 Vulkan 应用程序,想实现一个可以在任何地方自由移动的“飞行相机”。

我在场景中间放了一个可以飞来飞去的立方体。 相机位置完美无缺,但当我在立方体周围移动时,旋转行为很奇怪。 当我在立方体的另一侧时,我通过鼠标给出的向上和向下方向是相反的,当我在立方体的任一侧时,它们根本不起作用。在这两者之间的任何地方,它只会做奇怪的圈子。请注意,这只影响上下移动,不影响左右移动。

这是我的演示,我只在立方体的每一侧按此顺序上下移动鼠标(绕着它移动时除外)对于糟糕的帧率,我深表歉意,我有将其转换为 gif 并降低质量: https://imgur.com/HxknkQV

视频的快速解释: 首先,虽然看起来我左右移动了鼠标,但从侧面看并没有移动,但我没有。除了进入职位时,我每次都只是上下波动。另一件事是,虽然对于立方体的相反位置,它可能看起来旋转有效,但实际上是倒转的。

这是我的相机的代码:

#pragma once

#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/rotate_vector.hpp>



class Camera {

private:

    glm::mat4 _model;
    glm::mat4 _view;
    glm::mat4 _projection;
    
    glm::vec3 _position;
    glm::vec3 _up;

    glm::vec3 _moveSpeed = glm::vec3(0.08f);
    float _mouseSens = 0.005f;


public:
    glm::vec3 _direction;
    enum MovementType { FORWARD, BACKWARD, LEFT, RIGHT, UP, DOWN };


    Camera(uint32_t width, uint32_t height){

        _model = glm::mat4(1.0f);
        _projection = glm::perspective(glm::radians(90.0f), width / (float)height, 0.01f, 100.0f);
        _direction = glm::vec3(-2, 0, 0);
        _up = glm::vec3(0.0f, 0.0f, 1.0f);

        _position = glm::vec3(2.0f, 0.0f, 0.0f);

        _projection[1][1] *= -1; //Because Vulkan uses different axis, hence the up Vector being different to an OpenGL application for example
    }


    void rotate(float amount, glm::vec3 axis){

        _direction = glm::rotate(_direction, amount * _mouseSens, axis);
    }


    void move(MovementType movement) {

        switch (movement)
        {
        case FORWARD:
            _position += _direction * _moveSpeed;
            break;
        case BACKWARD:
            _position -= _direction * _moveSpeed;
            break;
        case LEFT:
            _position -= glm::normalize(glm::cross(_direction, _up)) * _moveSpeed;
            break;
        case RIGHT:
            _position += glm::normalize(glm::cross(_direction, _up)) * _moveSpeed;
            break;
        case UP:
            _position += _up * _moveSpeed;
            break;
        case DOWN:
            _position -= _up * _moveSpeed;
            break;
        }
    }


    glm::mat4 getMVP() {

        _view = glm::lookAt(_position, _position + _direction, _up);
        return _projection * _view * _model;
    }
};

任何帮助将不胜感激,因为我不太擅长向量和矩阵计算,而且真的不知道如何解决这个问题。谢谢

在我看来,就好像您在世界 space 中旋转相机一样(但我不能确定,因为调用 Camera::rotate 的代码未包含在您的问题中)。

如果我的假设是正确的,在相机中旋转 space 应该可以解决问题。 IE。假设 Camera::rotate 相对于当前相机 space 的轴执行旋转,您必须将其转换回世界 space,这可以通过 _view:

void rotate(float amount, glm::vec3 axis){
    auto directionCamSpace = glm::rotate(_direction, amount * _mouseSens, axis);
    _directionWorldSpace = glm::mat3(glm::inverse(_view)) * _direction;
}

然后使用 _directionWorldSpaceglm::lookAt:

glm::mat4 getMVP() {
    _view = glm::lookAt(_position, _position + _directionWorldSpace, _up);
    return _projection * _view * _model;
}

恐怕这可能不会引导您找到问题的最终解决方案,并且会出现 further/other 人工制品,但至少应该让您更进一步。

实现这种相机的最佳方法可能是使用四元数来跟踪相机的旋转,使用累积的四元数旋转来旋转相机的坐标系,然后使用 glm::inverse 来计算视图矩阵来自旋转相机的坐标系。 (用这种方法你根本不需要 glm::lookAt。)