【发布时间】:2018-04-02 10:37:12
【问题描述】:
我一直在按照教程学习 OpenGL,该教程位于 https://paroj.github.io/gltut/。
通过基础知识后,我在理解四元数及其与空间方向和变换的关系方面有点卡住了,尤其是从世界空间到相机空间,反之亦然。在Camera-Relative Orientation一章中,作者制作了一个相机,它在世界空间中相对于相机方向旋转模型。引用:
我们想要应用一个方向偏移 (R),它在相机空间中获取点。如果我们想将其应用于相机矩阵,只需将其乘以相机矩阵:R * C * O * p。这很好,但我们想对 O 应用变换,而不是对 C。
我未受过教育的猜测是,如果我们将偏移应用到相机空间,我们将获得第一人称相机。它是否正确?相反,偏移应用于 world 空间中的模型,使飞船相对于该空间而非相机空间旋转。我们只是观察它从相机空间旋转。
至少受到对四元数的一些理解的启发(或者我是这么认为的),我尝试实现第一人称相机。它有两个属性:
struct Camera{
glm::vec3 position; // Position in world space.
glm::quat orientation; // Orientation in world space.
}
位置会随着键盘动作而改变,而方向会因鼠标在屏幕上的移动而改变。
注意:GLM 重载了 glm::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;
}
方向和位置信息被传递给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));
结合模型、视图和投影矩阵并将结果传递给顶点着色器显示一切正常 - 就像人们期望从第一人称 POV 看到事物的方式一样。但是,当我添加鼠标移动,跟踪 x 和 y 方向的移动量时,事情变得一团糟。我想绕 world y 轴和 local 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
这里会出现什么问题? 我承认,我没有足够的知识来正确调试鼠标移动代码,我主要是照着说“右乘以在世界空间中应用偏移量,左乘以在相机空间中执行”。
我觉得我了解了一半,从有关该主题的大量电子资源中得出结论,同时得到更多的教育和更多的困惑。 感谢您的任何回答。
【问题讨论】: