Как интерполировать вращения?

У меня есть два вектора, описывающие повороты; начальное вращение A и целевое вращение B. Как мне лучше всего интерполировать A с коэффициентом F, чтобы приблизиться к B?

Использование простого lerp для векторов не работает, когда необходимо интерполировать более одного измерения (т. е. приводит к нежелательным поворотам). Возможно, построение кватернионов из векторов вращения и использование slerp — это правильный путь. Но как же тогда извлечь из полученного кватерниона вектор, описывающий новое вращение?

Заранее спасибо.


person uhuu    schedule 21.05.2010    source источник
comment
Можете ли вы объяснить немного лучше, почему SLERP не работает для вас? Что вы имеете в виду под интерполяцией более чем одного измерения, я полагаю, что оно просто начинается в одной точке (вектор A) и заканчивается в другой (вектор B), совершая кратчайший поворот вокруг начала координат.   -  person catchmeifyoutry    schedule 21.05.2010
comment
Под более чем одним измерением я подразумеваю более одной оси, например. одновременное вращение вокруг X и Y, а не просто вращение вокруг одной оси. И это когда LERP терпит неудачу.   -  person uhuu    schedule 21.05.2010
comment
По сути, это не имеет большого смысла, так как каждый поворот вокруг любого количества осей эквивалентен повороту вокруг какой-то другой оси. Так что на самом деле нет причин, по которым линейная интерполяция не работала бы во всех случаях.   -  person Joren    schedule 21.05.2010


Ответы (4)


Поскольку я, кажется, не понимаю вашего вопроса, вот небольшая реализация SLERP в python с использованием numpy . Я построил результаты, используя matplotlib (v.99 для Axes3D). Я не знаю, можете ли вы использовать python, но похоже ли это на вашу реализацию SLERP? Мне кажется, дает прекрасные результаты...

from numpy import *
from numpy.linalg import norm

def slerp(p0, p1, t):
        omega = arccos(dot(p0/norm(p0), p1/norm(p1)))
        so = sin(omega)
        return sin((1.0-t)*omega) / so * p0 + sin(t*omega)/so * p1


# test code
if __name__ == '__main__':
    pA = array([-2.0, 0.0, 2.0])
    pB = array([0.0, 2.0, -2.0])

    ps = array([slerp(pA, pB, t) for t in arange(0.0, 1.0, 0.01)])

    from pylab import *
    from mpl_toolkits.mplot3d import Axes3D
    f = figure()
    ax = Axes3D(f)
    ax.plot3D(ps[:,0], ps[:,1], ps[:,2], '.')
    show()
person catchmeifyoutry    schedule 21.05.2010
comment
Есть ли какая-то причина, по которой вы не делите все на so? Численная стабильность...? - person Mateen Ulhaq; 10.06.2018

Простой LERP (и перенормировка) хорошо работают только тогда, когда векторы очень близки друг к другу, но приведут к нежелательным результатам, когда векторы будут дальше друг от друга.

Есть два варианта:

Простые кросс-произведения:

Определите ось n, которая ортогональна как A, так и B, используя векторное произведение (будьте внимательны, когда векторы выровнены) и рассчитайте угол a между A и B, используя скалярное произведение. Теперь вы можете просто приблизиться к B, изменив a от 0 до a (это будет aNew и применить вращение aNew< /em> вокруг оси n на A.

Кватернионы:

Вычислите кватернион q, который перемещает A в B, и интерполируйте q с тождественным кватернионом I, используя SLERP. Полученный кватернион qNew затем можно применить к A.

person Ben    schedule 09.08.2013

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

Также есть немного соответствующего кода здесь, хотя я не не знаю, соответствует ли это тому, как вы представляете свои данные.

person Andrew McGregor    schedule 21.05.2010
comment
Спасибо. Мне удалось получить вектор от Кватерниона. Настройка с использованием SLERP работает нормально, если я интерполирую только по одной оси. Однако, что весьма любопытно для меня, SLERP ведет себя примерно так же, как и простой векторный LERP, при использовании более чем одной оси, то есть вращение время от времени сильно скачет. Любые идеи? - person uhuu; 21.05.2010
comment
Похоже, вы получаете карданный замок; представление вращения в виде вектора работает только в том случае, если вы представляете его в правильных координатах: en.wikipedia.org/wiki/ Gimbal_lock - person Andrew McGregor; 21.05.2010
comment
Ухуу, не могли бы вы уточнить, что вы подразумеваете под вращением вокруг нескольких осей? Когда вы выполняете slerp между кватернионами a и b, вы вращаетесь вокруг одной оси; ось кватерниона c, где c = b * a^-1 - person SuperElectric; 18.08.2010

Если вы решили использовать кватернионы (которые будут очень хорошо работать), см. мой ответ здесь о ресурсах для реализации кватернионов: Вращение в OpenGL относительно окна просмотра

Вы должны найти множество примеров по ссылкам в этом посте.

person Xavier Ho    schedule 21.05.2010