C++ 使用glm的飞行摄像机表现得很怪异

C++ 使用glm的飞行摄像机表现得很怪异,c++,3d,camera,vulkan,glm-math,C++,3d,Camera,Vulkan,Glm Math,我正在开发一个Vulkan应用程序,希望实现一个可以在任何地方自由移动的“飞行相机” 我在场景中间放了一个立方体,我可以绕着它飞。 摄影机的位置工作得很好,但只要我在立方体周围移动,旋转的动作就会很奇怪。 当我在立方体的另一侧时,我通过鼠标给出的上下方向是颠倒的,当我在立方体的任意一侧时,它们根本不起作用。在这两者之间的任何地方,都会有奇怪的圆圈。请注意,这只影响上下移动,而不影响左右移动 这是一个演示,演示了它对我来说是什么样子,我只在立方体的每一侧按此顺序上下移动鼠标(除了在其周围移动时)。

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

我在场景中间放了一个立方体,我可以绕着它飞。 摄影机的位置工作得很好,但只要我在立方体周围移动,旋转的动作就会很奇怪。 当我在立方体的另一侧时,我通过鼠标给出的上下方向是颠倒的,当我在立方体的任意一侧时,它们根本不起作用。在这两者之间的任何地方,都会有奇怪的圆圈。请注意,这只影响上下移动,而不影响左右移动

这是一个演示,演示了它对我来说是什么样子,我只在立方体的每一侧按此顺序上下移动鼠标(除了在其周围移动时)。我为错误的帧速率道歉,我不得不将其转换为gif并降低质量:

视频的快速解释: 首先,虽然看起来好像我左右移动了鼠标,但看不到两边,但我没有。我每次只上下移动,除了移动到位置时。另一件事是,对于立方体的另一个位置,它可能看起来像是旋转在起作用,但实际上是反转的

这是我相机的代码:

#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;
    }
};

#pragma一次
#定义GLM\u力\u深度\u 0到\u 1
#包括
#包括
#包括
类摄像机{
私人:
glm::mat4_模型;
glm::mat4_视图;
glm::mat4_投影;
glm::vec3_位置;
glm::vec3_up;
glm::vec3 _moveSpeed=glm::vec3(0.08f);
浮点数=0.005f;
公众:
glm::vec3_方向;
枚举移动类型{向前、向后、向左、向右、向上、向下};
摄像机(uint32的宽度,uint32的高度){
_型号=glm::mat4(1.0f);
_投影=glm::透视(glm::弧度(90.0f),宽度/(浮动)高度,0.01f,100.0f);
_方向=glm::vec3(-2,0,0);
_up=glm::vec3(0.0f,0.0f,1.0f);
_位置=glm::vec3(2.0f,0.0f,0.0f);
_投影[1][1]*=-1;//因为Vulkan使用不同的轴,因此上方向向量与OpenGL应用程序不同
}
无效旋转(浮动量,glm::vec3轴){
_方向=glm::旋转(_方向,数量*_鼠标,轴);
}
无效移动(移动类型移动){
开关(移动)
{
案件转发:
_位置+=\u方向*\u移动速度;
打破
倒格:
_位置-=\u方向*\u移动速度;
打破
案例左:
_位置-=glm::规格化(glm::交叉(_方向,_向上))*_移动速度;
打破
案例权利:
_位置+=glm::规格化(glm::交叉(_方向,_向上))*_移动速度;
打破
个案:
_位置+=\u向上*\u移动速度;
打破
按大小写:
_位置-=\u向上*\u移动速度;
打破
}
}
glm::mat4 getMVP(){
_视图=glm::注视(_位置,_位置+_方向,_向上);
返回_投影*_视图*_模型;
}
};

任何帮助都将非常感谢,因为我在向量和矩阵计算方面不是很好,而且真的不知道如何解决这个问题。谢谢。

在我看来,您好像在世界空间中旋转摄影机(但我不能确定,因为调用
camera::rotate
的代码不包括在您的问题中)

如果我的假设是正确的,在相机空间中旋转应该可以解决问题。例如,假设
Camera::rotate
执行相对于当前摄影机空间轴的旋转,则必须将其转换回世界空间,这可以通过
\u view
的逆操作完成:

void rotate(float amount, glm::vec3 axis){
    auto directionCamSpace = glm::rotate(_direction, amount * _mouseSens, axis);
    _directionWorldSpace = glm::mat3(glm::inverse(_view)) * _direction;
}
然后使用
\u directionWorldSpace
glm::lookAt

glm::mat4 getMVP() {
    _view = glm::lookAt(_position, _position + _directionWorldSpace, _up);
    return _projection * _view * _model;
}
我担心这可能会导致您尚未找到问题的最终解决方案,并且会出现更多/其他人工制品,但至少会让您更进一步


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

嘿,非常感谢您的回复。我研究了很多四元数的例子,但是我没有实现它们。我发现很多资料都支持你所说的,使用基于四元数的相机是最好的解决方案,但由于我刚刚开始,学习更复杂的数学,如矩阵和四元数(仍在学校),我没有任何理论或实践经验。虽然我希望这不是一个很好的要求,但你能试着简单一点解释你的方法吗,或者用一些sudo代码?非常感谢,非常欢迎。一个使用四元数进行旋转的完全实现的相机可以在我正在处理的一个应用程序中找到。以下是中的相关代码。(为了完全掌握if的诀窍,你还需要看看父类
camera
transform
)解释一切是如何工作的可能超出了StackOverflow问题的范围,但我打赌你一定能找到一些关于线性代数的优秀教程。无论如何,尝试使用您已有的工具和知识开发解决方案可以学到很多东西。我已经用
getMVP()
的一个可能的更新实现扩展了我的答案。请让我知道这是否对您有效,或者是否有助于您改进
摄像头的实施!