interpolate between rotation matrices

后端 未结 2 1651
礼貌的吻别
礼貌的吻别 2020-12-28 10:19

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

相关标签:
2条回答
  • 2020-12-28 10:54

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

    0 讨论(0)
  • 2020-12-28 10:56

    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/

    0 讨论(0)
提交回复
热议问题