bla*_*iro 7 c++ opengl glm-math
我一直在按照位于https://paroj.github.io/gltut/的教程学习 OpenGL 。
通过基础知识后,我在理解四元数及其与空间方向和变换的关系方面遇到了一些困难,特别是从世界空间到相机空间,反之亦然。在“相机相对方向”一章中,作者制作了一个相机,它在世界空间中相对于相机方向旋转模型。引用:
我们想要应用方向偏移 (R),它在相机空间中获取点。如果我们想将其应用于相机矩阵,只需将其乘以相机矩阵:R * C * O * p。这很好,但我们想要将变换应用于 O,而不是 C。
我未经教育的猜测是,如果我们将偏移应用于相机空间,我们将获得第一人称相机。它是否正确?相反,偏移会应用于世界空间中的模型,使飞船相对于该空间而不是相机空间旋转。我们只是从相机空间观察它旋转。
至少受到对四元数的一些理解的启发(或者我是这么认为的),我尝试实现第一人称相机。它有两个属性:
struct Camera{
glm::vec3 position; // Position in world space.
glm::quat orientation; // Orientation in world space.
}
Run Code Online (Sandbox Code Playgroud)
位置会根据键盘操作进行修改,而方向会因鼠标在屏幕上的移动而发生变化。
注意:GLM 重载了*运算符 forglm::quat * glm::vec3和通过四元数旋转向量的关系( 的更紧凑形式v' = qvq^-1)
例如,向前移动和向右移动:
glm::vec3 worldOffset;
float scaleFactor = 0.5f;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
worldOffset = orientation * (axis_vectors[AxisVector::AXIS_Z_NEG]); // AXIS_Z_NEG = glm::vec3(0, 0, -1)
position += worldOffset * scaleFactor;
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
worldOffset = orientation * (axis_vectors[AxisVector::AXIS_X_NEG]); // AXIS_Z_NEG = glm::vec3(-1, 0, 0)
position += worldOffset * scaleFactor;
}
Run Code Online (Sandbox Code Playgroud)
方向和位置信息被传递到glm::lookAt矩阵以构建世界到相机的转换,如下所示:
auto camPosition = position;
auto camForward = orientation * glm::vec3(0.0, 0.0, -1.0);
viewMatrix = glm::lookAt(camPosition, camPosition + camForward, glm::vec3(0.0, 1.0, 0.0));
Run Code Online (Sandbox Code Playgroud)
组合模型、视图和投影矩阵并将结果传递给顶点着色器可以正常显示所有内容 - 人们期望从第一人称 POV 中看到事物的方式。然而,当我添加鼠标移动并跟踪 x 和 y 方向的移动量时,事情会变得混乱。我想绕世界y 轴和局部x 轴旋转:
auto xOffset = glm::angleAxis(xAmount, axis_vectors[AxisVector::AXIS_Y_POS]); // mouse movement in x-direction
auto yOffset = glm::angleAxis(yAmount, axis_vectors[AxisVector::AXIS_X_POS]); // mouse movement in y-direction
orientation = orientation * xOffset; // Works OK, can look left/right
orientation = yOffset * orientation; // When adding this line, things get ugly
Run Code Online (Sandbox Code Playgroud)
这里会出现什么问题呢?我承认,我没有足够的知识来正确调试鼠标移动代码,我主要遵循以下几行:“右乘以在世界空间中应用偏移,左乘以在相机空间中执行此操作。”
我觉得我对事情了解得半途而废,从大量有关该主题的电子资源中得出结论,同时获得了更多的教育,同时也更加困惑。感谢您的任何答复。
Ian*_*ung 10
旋转表示方向的 glm 四元数:
//Precomputation:
//pitch (rot around x in radians),
//yaw (rot around y in radians),
//roll (rot around z in radians)
//are computed/incremented by mouse/keyboard events
Run Code Online (Sandbox Code Playgroud)
计算视图矩阵:
void CameraFPSQuaternion::UpdateView()
{
//FPS camera: RotationX(pitch) * RotationY(yaw)
glm::quat qPitch = glm::angleAxis(pitch, glm::vec3(1, 0, 0));
glm::quat qYaw = glm::angleAxis(yaw, glm::vec3(0, 1, 0));
glm::quat qRoll = glm::angleAxis(roll,glm::vec3(0,0,1));
//For a FPS camera we can omit roll
glm::quat orientation = qPitch * qYaw;
orientation = glm::normalize(orientation);
glm::mat4 rotate = glm::mat4_cast(orientation);
glm::mat4 translate = glm::mat4(1.0f);
translate = glm::translate(translate, -eye);
viewMatrix = rotate * translate;
}
Run Code Online (Sandbox Code Playgroud)
如果你想存储四元数,那么只要偏航、俯仰或滚动改变就重新计算它:
void CameraFPSQuaternion::RotatePitch(float rads) // rotate around cams local X axis
{
glm::quat qPitch = glm::angleAxis(rads, glm::vec3(1, 0, 0));
m_orientation = glm::normalize(qPitch) * m_orientation;
glm::mat4 rotate = glm::mat4_cast(m_orientation);
glm::mat4 translate = glm::mat4(1.0f);
translate = glm::translate(translate, -eye);
m_viewMatrix = rotate * translate;
}
Run Code Online (Sandbox Code Playgroud)
如果你想给出绕给定轴的旋转速度,可以使用 slerp:
void CameraFPSQuaternion::Update(float deltaTimeSeconds)
{
//FPS camera: RotationX(pitch) * RotationY(yaw)
glm::quat qPitch = glm::angleAxis(m_d_pitch, glm::vec3(1, 0, 0));
glm::quat qYaw = glm::angleAxis(m_d_yaw, glm::vec3(0, 1, 0));
glm::quat qRoll = glm::angleAxis(m_d_roll,glm::vec3(0,0,1));
//For a FPS camera we can omit roll
glm::quat m_d_orientation = qPitch * qYaw;
glm::quat delta = glm::mix(glm::quat(0,0,0,0),m_d_orientation,deltaTimeSeconds);
m_orientation = glm::normalize(delta) * m_orientation;
glm::mat4 rotate = glm::mat4_cast(orientation);
glm::mat4 translate = glm::mat4(1.0f);
translate = glm::translate(translate, -eye);
viewMatrix = rotate * translate;
}
Run Code Online (Sandbox Code Playgroud)