glm::quatLookAt Return 一个 NaN 四元数
glm::quatLookAt Return a NaN quaternion
我有一个计算四元数的 LookAt 函数(取自 here):
Camera& Camera::LookAt(const glm::vec3& lookat)noexcept{
glm::vec3 direction = lookat - transform.GetPosition();
float directionLength = glm::length(direction);
if(!(directionLength > 0.0001)){ // Check if the direction is valid; Also deals with NaN
transform.SetRotation(glm::quat(1, 0, 0, 0));
return *this;
}
direction /= directionLength; // Normalize direction
if(glm::abs(glm::dot(direction, transform.GetWorldUp())) > .9999f) {
transform.SetRotation(glm::inverse(glm::quatLookAt(direction, transform.GetUp())));// Use relative up
} else {
transform.SetRotation(glm::inverse(glm::quatLookAt(direction, transform.GetWorldUp())));
}
return *this;
}
出于某种原因,当相机的第一个位置为 0 0 20(四元数为 1 0 0 0)并且我将其更改为 0 20 0 并调用 LookAt() 时,我的四元数最终只有 NaN。如果相机的第一个位置不是 0 0 20(或 20 0 0),它工作正常。
这是我的控制台(我在转换之前向 LookAt 函数添加了一些 std::cout):
我不知道发生了什么,有人可以帮助我吗?
编辑:
这是我写的新函数,它检查两个方向是否平行。如果是,它会稍微改变方向以防止平行:
Camera& Camera::LookAt(const glm::vec3& lookat)noexcept{
glm::vec3 direction = glm::normalize( lookat - transform.GetPosition());
if(!(glm::length(direction) > 0.0001)){ // Check if the direction is valid; Also deals with NaN
transform.SetRotation(glm::quat(1, 0, 0, 0));
return *this;
}
//Check if We must use relative Up
glm::vec3 upToUse = transform.GetWorldUp();
if(glm::abs(glm::dot(direction, transform.GetWorldUp())) > .9999f) upToUse = transform.GetUp();
//Check if parallel
if(glm::vec3(0.0f) == glm::cross(transform.GetUp(),direction) ) direction = glm::normalize(lookat - (transform.GetPosition() + glm::vec3(0.001f,0.0f,0.001f))); //Change position and recalculate direction
//Calcul new quaternion
transform.SetRotation(glm::inverse(glm::quatLookAt(direction, upToUse)));
return *this;
}
您要求 GLM 创建一个四元数,使 Z 方向为 (0, -1, 0)(方向向量),Y 方向也为 (0, 1, 0)(向上向量)。
这是不可能的。任何旋转都不会使 Y 轴和 Z 轴指向彼此相反的方向。您需要指定一个不同的向上矢量。
请注意,向上向量不必垂直于方向向量,因为 GLM 会忽略不垂直的部分。但它必须至少有一点垂直。
我有一个计算四元数的 LookAt 函数(取自 here):
Camera& Camera::LookAt(const glm::vec3& lookat)noexcept{
glm::vec3 direction = lookat - transform.GetPosition();
float directionLength = glm::length(direction);
if(!(directionLength > 0.0001)){ // Check if the direction is valid; Also deals with NaN
transform.SetRotation(glm::quat(1, 0, 0, 0));
return *this;
}
direction /= directionLength; // Normalize direction
if(glm::abs(glm::dot(direction, transform.GetWorldUp())) > .9999f) {
transform.SetRotation(glm::inverse(glm::quatLookAt(direction, transform.GetUp())));// Use relative up
} else {
transform.SetRotation(glm::inverse(glm::quatLookAt(direction, transform.GetWorldUp())));
}
return *this;
}
出于某种原因,当相机的第一个位置为 0 0 20(四元数为 1 0 0 0)并且我将其更改为 0 20 0 并调用 LookAt() 时,我的四元数最终只有 NaN。如果相机的第一个位置不是 0 0 20(或 20 0 0),它工作正常。
这是我的控制台(我在转换之前向 LookAt 函数添加了一些 std::cout):
我不知道发生了什么,有人可以帮助我吗?
编辑:
这是我写的新函数,它检查两个方向是否平行。如果是,它会稍微改变方向以防止平行:
Camera& Camera::LookAt(const glm::vec3& lookat)noexcept{
glm::vec3 direction = glm::normalize( lookat - transform.GetPosition());
if(!(glm::length(direction) > 0.0001)){ // Check if the direction is valid; Also deals with NaN
transform.SetRotation(glm::quat(1, 0, 0, 0));
return *this;
}
//Check if We must use relative Up
glm::vec3 upToUse = transform.GetWorldUp();
if(glm::abs(glm::dot(direction, transform.GetWorldUp())) > .9999f) upToUse = transform.GetUp();
//Check if parallel
if(glm::vec3(0.0f) == glm::cross(transform.GetUp(),direction) ) direction = glm::normalize(lookat - (transform.GetPosition() + glm::vec3(0.001f,0.0f,0.001f))); //Change position and recalculate direction
//Calcul new quaternion
transform.SetRotation(glm::inverse(glm::quatLookAt(direction, upToUse)));
return *this;
}
您要求 GLM 创建一个四元数,使 Z 方向为 (0, -1, 0)(方向向量),Y 方向也为 (0, 1, 0)(向上向量)。
这是不可能的。任何旋转都不会使 Y 轴和 Z 轴指向彼此相反的方向。您需要指定一个不同的向上矢量。
请注意,向上向量不必垂直于方向向量,因为 GLM 会忽略不垂直的部分。但它必须至少有一点垂直。