我正在尝试编写一个使用glm :: quat表示旋转的lookat函数,基于此answer。然而,遇到正确的角度我遇到了麻烦。这是我的lookat函数:
void Camera::LookAt(float x, float y, float z) {
glm::vec3 lookVector = glm::vec3(x, y, z);
assert(lookVector != position);
glm::vec3 direction = glm::normalize(lookVector-position);
float dot = glm::dot(glm::vec3(0, 0, -1), direction);
if (fabs(dot - (-1.0f)) < 0.000001f)
rotation = glm::quat(RadiansToDegrees(M_PI), 0.0f, 1.0f, 0.0f);
if (fabs(dot - (1.0f)) < 0.000001f)
rotation = glm::quat();
float angle = RadiansToDegrees(acosf(dot));
glm::vec3 cross = (glm::cross(glm::vec3(0, 0, -1), direction));
rotation = glm::normalize(glm::angleAxis(angle, cross));
std::cout << glm::eulerAngles(rotation).x << " " << glm::eulerAngles(rotation).y << " " << glm::eulerAngles(rotation).z << "\n";
}
当我的相机处于(0.0f,0.0f,-10.0f)时,当我调用LookAt(0.0f,0.0f,0.0f)时,会输出正确的0,0,0旋转。但是,如果我将相机转换为(0.0f,-0.01f,-10.0f)或更高,我会得到大约124,0,0的旋转。如果我继续将y翻译为-0.01f,这会下降。如果我没有规范化四元数,我就不会遇到这个问题。围绕x轴旋转仍然是124,但外观很好。但是,如果我稍后将四元数标准化,它再次显示为旋转到大约124.我无法规范化cross
,因为这样做会抛出一个断言。什么会导致我从我的lookat函数得到大约124的euler角度,我该如何解决?
答案 0 :(得分:4)
从版本0.9.9.0开始,<glm/gtx/quaternion.hpp>
中的一个函数主要执行您想要的操作:
template<typename T, qualifier Q>
tquat<T, Q> quatLookAt(vec<3, T, Q> const& direction, vec<3, T, Q> const& up);
由this pull request添加,并于2017年7月24日合并为主人。
<强>但是强>:
所以你可能想在函数周围编写一个更安全的包装器:
glm::quat safeQuatLookAt(
glm::vec3 const& lookFrom,
glm::vec3 const& lookTo,
glm::vec3 const& up,
glm::vec3 const& alternativeUp)
{
glm::vec3 direction = lookTo - lookFrom;
float directionLength = glm::length(direction);
// Check if the direction is valid; Also deals with NaN
if(!(directionLength > 0.0001))
return glm::quat(1, 0, 0, 0); // Just return identity
// Normalize direction
direction /= directionLength;
// Is the normal up (nearly) parallel to direction?
if(glm::abs(glm::dot(direction, up)) > .9999f) {
// Use alternative up
return glm::quatLookAt(direction, alternativeUp);
}
else {
return glm::quatLookAt(direction, up);
}
}
答案 1 :(得分:2)
我已使用以下代码解决了问题:
void Camera::LookAt(float x, float y, float z) {
glm::vec3 lookVector = glm::vec3(x, y, z);
assert(lookVector != position);
glm::vec3 direction = glm::normalize(lookVector-position);
float dot = glm::dot(glm::vec3(0, 0, 1), direction);
if (fabs(dot - (-1.0f)) < 0.000001f) {
rotation = glm::angleAxis(RadiansToDegrees(M_PI), glm::vec3(0, 1, 0));
return;
}
else if (fabs(dot - (1.0f)) < 0.000001f) {
rotation = glm::quat();
return;
}
float angle = -RadiansToDegrees(acosf(dot));
glm::vec3 cross = glm::normalize(glm::cross(glm::vec3(0, 0, 1), direction));
rotation = glm::normalize(glm::angleAxis(angle, cross));
}
但我不理解angle
上否定的必要性。它解决了我的最后一个问题,并解释了为什么会有用的数学。