GLM如何使用vec3创建旋转矩阵

7

我正在制作一款游戏,需要使弹射物面向其前进方向。我知道它的前进方向,需要制作一个变换矩阵,使我能够将弹射物模型方向(1,0,0)或正X轴与任意向量对齐。在glm中如何做到这一点?

3个回答

7
你是如何准确表示方向的呢?可以这样做:

你可以像这样:

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
)

1
非常感谢。愿您的日子充满繁荣。 - Rotartsi

7

嘿,我找到了答案,与@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);

希望这能对某人有所帮助!


0

其他答案都不是真正的完整答案,因为它们没有处理像 cross(.,.)=0up||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);
    }
}

这种解决方案的另一个缺点是它非常“突兀”,即只有在矩阵爆炸时才触发特殊情况。这可能会导致在处理接近平行情况的情况时出现伪影。通常,人们希望在重叠区域之间进行过渡,并在每个区域应用连续的解决方案。为此,将其分解为欧拉角可能更好。如果有人跨越任何这样的算法,请发布。我的意思是这对学生来说也是一个不错的作业。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接