在旋转矩阵之间进行插值

发布于 2024-09-30 19:45:36 字数 166 浏览 1 评论 0原文

我有两个描述任意旋转的旋转矩阵。 (4x4 opengl 兼容)

现在我想在它们之间进行插值,以便它遵循从一个旋转到另一个旋转的径向路径。想象一下三脚架上的相机朝一个方向看然后旋转。

如果我对每个分量进行插值,我会得到一个挤压结果,所以我认为我只需要对矩阵的某些分量进行插值。但哪些呢?

i have two rotation matrices that describe arbitrary rotations. (4x4 opengl compatible)

now i want to interpolate between them, so that it follows a radial path from one rotation to the other. think of a camera on a tripod looking one way and then rotating.

if i interpolate every component i get a squeezing result, so i think i need to interpolate only certain components of the matrix. but which ones?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

樱&纷飞 2024-10-07 19:45:36

您必须对矩阵的旋转部分使用 SLERP,对其他部分使用线性。最好的方法是将矩阵转换为四元数并使用(更简单的)四元数 SLERP:http://en .wikipedia.org/wiki/Slerp

我建议阅读 Graphic Gems II 或 III,特别是有关将矩阵分解为更简单的变换的部分。以下是 Spencer W. Thomas 的本章来源:

http://tog.acm .org/resources/GraphicsGems/gemsii/unmatrix.c

当然,我建议您自己学习如何做到这一点。其实没那么难,只是有很多烦人的代数。最后,这里有一篇关于如何通过 Id 软件将矩阵转换为四元数并转换回来的精彩论文:http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf


<编辑:这是几乎每个人都引用的公式,它来自 1985 年的 SIGGRAPH 论文。

alt text

位置

- qm = interpolated quaternion
- qa = quaternion a (first quaternion to be interpolated between)
- qb = quaternion b (second quaternion to be interpolated between)
- t = a scalar between 0.0 (at qa) and 1.0 (at qb)
- θ is half the angle between qa and qb

代码:

quat slerp(quat qa, quat qb, double t) {
    // quaternion to return
    quat qm = new quat();
    // Calculate angle between them.
    double cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
    // if qa=qb or qa=-qb then theta = 0 and we can return qa
    if (abs(cosHalfTheta) >= 1.0){
        qm.w = qa.w;qm.x = qa.x;qm.y = qa.y;qm.z = qa.z;
        return qm;
    }
    // Calculate temporary values.
    double halfTheta = acos(cosHalfTheta);
    double sinHalfTheta = sqrt(1.0 - cosHalfTheta*cosHalfTheta);
    // if theta = 180 degrees then result is not fully defined
    // we could rotate around any axis normal to qa or qb
    if (fabs(sinHalfTheta) < 0.001){ // fabs is floating point absolute
        qm.w = (qa.w * 0.5 + qb.w * 0.5);
        qm.x = (qa.x * 0.5 + qb.x * 0.5);
        qm.y = (qa.y * 0.5 + qb.y * 0.5);
        qm.z = (qa.z * 0.5 + qb.z * 0.5);
        return qm;
    }
    double ratioA = sin((1 - t) * halfTheta) / sinHalfTheta;
    double ratioB = sin(t * halfTheta) / sinHalfTheta; 
    //calculate Quaternion.
    qm.w = (qa.w * ratioA + qb.w * ratioB);
    qm.x = (qa.x * ratioA + qb.x * ratioB);
    qm.y = (qa.y * ratioA + qb.y * ratioB);
    qm.z = (qa.z * ratioA + qb.z * ratioB);
    return qm;
}

来自:http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/

You have to use SLERP for the rotational parts of the matrices, and linear for the other parts. The best way is to turn your matrices into quaternions and use the (simpler) quaternion SLERP: http://en.wikipedia.org/wiki/Slerp.

I suggest reading Graphic Gems II or III,specifically the sections about decomposing matrices into simpler transformations. Here's Spencer W. Thomas' source for this chapter:

http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c

Of course, I suggest you learn how to do this yourself. It's really not that hard, just a lot of annoying algebra. And finally, here's a great paper on how to turn a matrix into a quaternion, and back, by Id software: http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf


Edit: This is the formula pretty much everyone cites, it's from a 1985 SIGGRAPH paper.

alt text

Where:

- qm = interpolated quaternion
- qa = quaternion a (first quaternion to be interpolated between)
- qb = quaternion b (second quaternion to be interpolated between)
- t = a scalar between 0.0 (at qa) and 1.0 (at qb)
- θ is half the angle between qa and qb

Code:

quat slerp(quat qa, quat qb, double t) {
    // quaternion to return
    quat qm = new quat();
    // Calculate angle between them.
    double cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
    // if qa=qb or qa=-qb then theta = 0 and we can return qa
    if (abs(cosHalfTheta) >= 1.0){
        qm.w = qa.w;qm.x = qa.x;qm.y = qa.y;qm.z = qa.z;
        return qm;
    }
    // Calculate temporary values.
    double halfTheta = acos(cosHalfTheta);
    double sinHalfTheta = sqrt(1.0 - cosHalfTheta*cosHalfTheta);
    // if theta = 180 degrees then result is not fully defined
    // we could rotate around any axis normal to qa or qb
    if (fabs(sinHalfTheta) < 0.001){ // fabs is floating point absolute
        qm.w = (qa.w * 0.5 + qb.w * 0.5);
        qm.x = (qa.x * 0.5 + qb.x * 0.5);
        qm.y = (qa.y * 0.5 + qb.y * 0.5);
        qm.z = (qa.z * 0.5 + qb.z * 0.5);
        return qm;
    }
    double ratioA = sin((1 - t) * halfTheta) / sinHalfTheta;
    double ratioB = sin(t * halfTheta) / sinHalfTheta; 
    //calculate Quaternion.
    qm.w = (qa.w * ratioA + qb.w * ratioB);
    qm.x = (qa.x * ratioA + qb.x * ratioB);
    qm.y = (qa.y * ratioA + qb.y * ratioB);
    qm.z = (qa.z * ratioA + qb.z * ratioB);
    return qm;
}

From: http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/

草莓酥 2024-10-07 19:45:36

您需要将矩阵转换为不同的表示形式 - 四元数对此很有效,并且插值四元数是一种明确定义的操作。

You need to convert the matrix into a different representation - quaternions work well for this, and interpolating quaternions is a well-defined operation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文