【发布时间】:2012-08-30 23:13:53
【问题描述】:
在弄清楚我之前的question 的答案后,我发现原因是某种数学上的怪异。
使用 GLM (OpenGL) 库,我创建如下方向
glm::gtx::quaternion::orientation =
glm::gtx::quaternion::angleAxis(pitchAccum, 1.0f, 0.0f, 0.0f) *
glm::gtx::quaternion::angleAxis(yawAccum, 0.0f, 1.0f, 0.0f);
现在,如果我从这个方向创建一个矩阵,它不再是列主要的,而是以某种方式成为行主要的
glm::mat4 view = glm::gtx::quaternion::toMat4(orientation);
换句话说,通过使用行主索引访问矩阵来找到 3 个坐标轴
view[0][0], view[1][0], view[2][0] // X axis
view[0][1], view[1][1], view[2][1] // Y axis
view[0][2], view[1][2], view[2][2] // Z axis
也就是旋转部分的转置。
矩阵的平移部分仍应使用主要列设置,以使最终视图矩阵按预期工作。
view[3][0] = -glm::dot(glm::vec3(view[0][0], view[1][0], view[2][0]), position); // Right
view[3][1] = -glm::dot(glm::vec3(view[0][1], view[1][1], view[2][1]), position); // Up
view[3][2] = -glm::dot(glm::vec3(view[0][2], view[1][2], view[2][2]), position); // Forward
为什么在使用方向时旋转矩阵会从主要列翻转到主要行(转置?)?
编辑:
// Move forward
if (glfwGetKey('W') == GLFW_PRESS)
{
//movement += glm::vec3(view[2][0], view[2][1], view[2][2]); // incorrect
movement += -glm::vec3(view[0][2], view[1][2], view[2][2]); // correct
}
// Move backward
if (glfwGetKey('S') == GLFW_PRESS)
{
//movement += -glm::vec3(view[2][0], view[2][1], view[2][2]); // incorrect
movement += glm::vec3(view[0][2], view[1][2], view[2][2]); // correct
}
// Strafe left
if (glfwGetKey('A') == GLFW_PRESS)
{
//movement += -glm::vec3(view[0][0], view[0][1], view[0][2]); // incorrect
movement += -glm::vec3(view[0][0], view[1][0], view[2][0]); // correct
}
// Strafe right
if (glfwGetKey('D') == GLFW_PRESS)
{
//movement += glm::vec3(view[0][0], view[0][1], view[0][2]); // incorrect
movement += glm::vec3(view[0][0], view[1][0], view[2][0]); // correct
}
【问题讨论】:
-
是什么让你说它被翻转了?这是一个旋转矩阵;它的转置也是它的逆。这意味着您可能只是看到旋转方向不是您所期望的。
-
另外,请停止使用欧拉角。是的,即使您使用四元数,您仍在使用它们。
-
是什么让你说它被翻转了? 旋转轴只有在使用行主要方法访问时才是正确的。它们没有以列主要方式存储,考虑到库处理 OpenGL,这很奇怪。
-
另外,请不要再使用欧拉角了。你能指出一个不使用欧拉角的例子吗,我理解后会实现它吗?
-
@NicolBolas 我也想知道使用欧拉角和四元数的替代方案;由于四元数基本上表示为轴向量和围绕该向量的旋转角度 (x,y,z,w),这可以解释为什么库中如此多的四元数生成函数采用规则角度。如果您提到了更好的方法,了解它是什么会有所帮助。