c++ - 使用 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;
}
};
任何帮助将不胜感激,因为我在向量和矩阵计算方面并不是那么好,而且真的不知道如何解决这个问题。谢谢。
解决方案
在我看来,您好像在世界空间中旋转相机(但我无法确定,因为调用的代码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;
}
然后使用_directionWorldSpace
with glm::lookAt
:
glm::mat4 getMVP() {
_view = glm::lookAt(_position, _position + _directionWorldSpace, _up);
return _projection * _view * _model;
}
恐怕这可能不会导致您最终解决问题,并且会出现更多/其他伪影,但它至少应该让您更进一步。
实现这种相机的最佳方法可能是使用四元数来跟踪相机的旋转,使用累积的四元数旋转glm::inverse
来旋转相机的坐标系,然后使用旋转后的相机坐标系计算视图矩阵。(你根本不需要glm::lookAt
这种方法。)
推荐阅读
- python - 如何通过networkx使用邻接矩阵将图形转换为所有路径的列表?
- sql - 加快我的 SQL 查询?它给出了执行超时错误
- mongodb - 如何在 MongoDB 中识别 Int 日期格式
- docker - Hugo 主题链接是指 Docker/Nginx 中的容器端口
- mysql - sql为每个分组列和其余行选择最大值
- macros - 我可以在 Elixir 中另一个宏的引用中扩展一个宏吗?
- android - 如何从安卓相机拍摄完整的 360 度全景照片?
- azure - Azure 函数输出绑定参数名称不包含在 context.bindings 中
- innodb - 当主键更改时,mvcc 如何工作?
- certificate - 证书签名请求的哪一部分在签名之前被散列?