Подтвердить что ты не робот

Интерполировать между матрицами вращения

i имеют две матрицы вращения, которые описывают произвольные вращения. (Совместим с 4x4 opengl)

теперь я хочу интерполировать между ними, чтобы он следовал радиальному пути от одного поворота к другому. подумайте о том, что камера на штативе смотрит в одну сторону, а затем вращается.

Если я интерполирую каждый компонент, я получаю результат сжатия, поэтому я думаю, что мне нужно интерполировать только определенные компоненты матрицы. но какие?

4b9b3361

Ответ 1

Вы должны использовать SLERP для вращательных частей матриц и линейно для других частей. Лучший способ - превратить ваши матрицы в кватернионы и использовать (более простой) кватернион SLERP: http://en.wikipedia.org/wiki/Slerp.

Я предлагаю прочитать Graphic Gems II или III, в частности разделы о разложении матриц на более простые преобразования. Здесь источник Спенсера У. Томаса для этой главы:

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

Конечно, я предлагаю вам научиться делать это самостоятельно. Это действительно не так сложно, просто много раздражающей алгебры. И наконец, вот замечательная статья о том, как превратить матрицу в кватернион и обратно, с помощью программного обеспечения Id: http://cache-www.intel.com/cd/00/00/29/37/293748_293748.pdf


Изменить. Это формула, которую все цитируют, из статьи SIGGRAPH 1985 года.

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/

Ответ 2

Вам нужно преобразовать матрицу в другое представление - кватернионы хорошо работают для этого, а интерполирующие кватернионы - это четко определенная операция.