GLM 从 vec3 生成旋转矩阵
GLM Make Rotation Matrix from vec3
我正在制作一个游戏,我需要弹丸朝向它前进的方向。我知道它的前进方向,我需要制作一个变换矩阵,使我能够将射弹模型方向 (1, 0, 0) 或正 X 轴与任意向量对齐。我怎么能在 glm 中做到这一点?
你用什么来准确表示方向?
你可以这样做:
glm::mat4 transform = glm::eulerAngleYXZ(euler.y, euler.x, euler.z);
或通过四元数:
glm::quat rot = glm::angleAxis(glm::radians(angle_in_degrees), glm::vec3(x, y, z));
glm::mat4 rotMatrix = glm::mat4_cast(rot);
除非您正在寻找像 glm::lookAt
这样简单的东西?
detail::tmat4x4<T> glm::gtc::matrix_transform::lookAt
(
detail::tvec3< T > const & eye, // from
detail::tvec3< T > const & center, // to
detail::tvec3< T > const & up // up
)
嘿,我找到了答案,接近@Mr_Pouet,但这里是:
const glm::vec3 a = ...;
const glm::vec3 b = ...; // in my case (1, 0, 0)
glm::vec3 v = glm::cross(b, a);
float angle = acos(glm::dot(b, a) / (glm::length(b) * glm::length(a)));
glm::mat4 rotmat = glm::rotate(angle, v);
您可以将 a 或 b 替换为您想要的任何内容,其中 a 是您要转换到的向量,b 是您所在的位置。如果 b 是 (1, 0, 0) 或 x 轴,我们可以优化它,就像我的例子:
glm::vec3 v = glm::vec3(0, -a.z, a.y);
float angle = acos(a.x / glm::length(a));
glm::mat4 rotmat = glm::rotate(angle, v);
希望对大家有所帮助!
None 的其他答案确实是完整的答案,因为它们不处理像 cross(.,.)=0
或 up||at-eye
.
这样的特殊情况
这是一个相当完整的解决方案,适用于您不关心旋转对象(即直线或圆柱体等)方向的所有情况:
glm::vec3 from;
glm::vec3 to;
glm::vec3 v = glm::cross(to, from);
float angle = acos(glm::dot(to, from) / (glm::length(to) * glm::length(from)));
glm::mat4 rotmat = glm::rotate(angle, v);
// special cases lead to NaN values in the rotation matrix
if (glm::any(glm::isnan(rotmat * glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)))) {
if (angle < 0.1f) {
rotmat = glm::mat4(1.0f);
}
else if (angle > 3.1f) {
// rotate about any perpendicular vector
rotmat = glm::rotate(angle, glm::cross(from,
glm::vec3(from.y, from.z, from.x)));
}
else {
assert(false);
}
}
此解决方案的另一个缺点是它非常 'snappy',即。特殊情况仅在矩阵爆炸时触发。在处理接近平行案例的案例时,这可能会导致伪影。通常,人们会希望在重叠区域之间过渡并在每个区域中应用连续解决方案。为此,我猜最好分解成欧拉角。如果有人越过任何此类算法,请post。我的意思是这对学生来说也是一个不错的家庭作业。
我正在制作一个游戏,我需要弹丸朝向它前进的方向。我知道它的前进方向,我需要制作一个变换矩阵,使我能够将射弹模型方向 (1, 0, 0) 或正 X 轴与任意向量对齐。我怎么能在 glm 中做到这一点?
你用什么来准确表示方向?
你可以这样做:
glm::mat4 transform = glm::eulerAngleYXZ(euler.y, euler.x, euler.z);
或通过四元数:
glm::quat rot = glm::angleAxis(glm::radians(angle_in_degrees), glm::vec3(x, y, z));
glm::mat4 rotMatrix = glm::mat4_cast(rot);
除非您正在寻找像 glm::lookAt
这样简单的东西?
detail::tmat4x4<T> glm::gtc::matrix_transform::lookAt
(
detail::tvec3< T > const & eye, // from
detail::tvec3< T > const & center, // to
detail::tvec3< T > const & up // up
)
嘿,我找到了答案,接近@Mr_Pouet,但这里是:
const glm::vec3 a = ...;
const glm::vec3 b = ...; // in my case (1, 0, 0)
glm::vec3 v = glm::cross(b, a);
float angle = acos(glm::dot(b, a) / (glm::length(b) * glm::length(a)));
glm::mat4 rotmat = glm::rotate(angle, v);
您可以将 a 或 b 替换为您想要的任何内容,其中 a 是您要转换到的向量,b 是您所在的位置。如果 b 是 (1, 0, 0) 或 x 轴,我们可以优化它,就像我的例子:
glm::vec3 v = glm::vec3(0, -a.z, a.y);
float angle = acos(a.x / glm::length(a));
glm::mat4 rotmat = glm::rotate(angle, v);
希望对大家有所帮助!
None 的其他答案确实是完整的答案,因为它们不处理像 cross(.,.)=0
或 up||at-eye
.
这是一个相当完整的解决方案,适用于您不关心旋转对象(即直线或圆柱体等)方向的所有情况:
glm::vec3 from;
glm::vec3 to;
glm::vec3 v = glm::cross(to, from);
float angle = acos(glm::dot(to, from) / (glm::length(to) * glm::length(from)));
glm::mat4 rotmat = glm::rotate(angle, v);
// special cases lead to NaN values in the rotation matrix
if (glm::any(glm::isnan(rotmat * glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)))) {
if (angle < 0.1f) {
rotmat = glm::mat4(1.0f);
}
else if (angle > 3.1f) {
// rotate about any perpendicular vector
rotmat = glm::rotate(angle, glm::cross(from,
glm::vec3(from.y, from.z, from.x)));
}
else {
assert(false);
}
}
此解决方案的另一个缺点是它非常 'snappy',即。特殊情况仅在矩阵爆炸时触发。在处理接近平行案例的案例时,这可能会导致伪影。通常,人们会希望在重叠区域之间过渡并在每个区域中应用连续解决方案。为此,我猜最好分解成欧拉角。如果有人越过任何此类算法,请post。我的意思是这对学生来说也是一个不错的家庭作业。