使用 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;
}
然后使用 _directionWorldSpace
和 glm::lookAt
:
glm::mat4 getMVP() {
_view = glm::lookAt(_position, _position + _directionWorldSpace, _up);
return _projection * _view * _model;
}
恐怕这可能不会引导您找到问题的最终解决方案,并且会出现 further/other 人工制品,但至少应该让您更进一步。
实现这种相机的最佳方法可能是使用四元数来跟踪相机的旋转,使用累积的四元数旋转来旋转相机的坐标系,然后使用 glm::inverse
来计算视图矩阵来自旋转相机的坐标系。 (用这种方法你根本不需要 glm::lookAt
。)
我正在开发一个 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;
}
然后使用 _directionWorldSpace
和 glm::lookAt
:
glm::mat4 getMVP() {
_view = glm::lookAt(_position, _position + _directionWorldSpace, _up);
return _projection * _view * _model;
}
恐怕这可能不会引导您找到问题的最终解决方案,并且会出现 further/other 人工制品,但至少应该让您更进一步。
实现这种相机的最佳方法可能是使用四元数来跟踪相机的旋转,使用累积的四元数旋转来旋转相机的坐标系,然后使用 glm::inverse
来计算视图矩阵来自旋转相机的坐标系。 (用这种方法你根本不需要 glm::lookAt
。)