首页 > 解决方案 > 使用 glm 的飞行相机表现得很奇怪

问题描述

我正在开发一个 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;
    }
};

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

标签: c++3dcameravulkanglm-math

解决方案


在我看来,您好像在世界空间中旋转相机(但我无法确定,因为调用的代码Camera::rotate不包含在您的问题中)。

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

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

然后使用_directionWorldSpacewith glm::lookAt

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

恐怕这可能不会导致您最终解决问题,并且会出现更多/其他伪影,但它至少应该让您更进一步。

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


推荐阅读