Почему при вращении кватерниона в определенных направлениях возникает внезапный поворот / крен? - PullRequest
0 голосов
/ 27 ноября 2018

Сценарий

Учитывая нормализованный кватернион A_q и нормализованный вектор направления B_v, мы рассчитываем новый поворот C_q, который будет вращать A_q в «грань» внаправление B_v.Для пояснения, пусть D_q = C_q * A_q так, что (1,0,0) с поворотом на D_q будет равно B_v.

NB. Для удобства обозначения отныне мы будем ссылаться на (1,0,0), повернутый любым кватернионом, как символ этого кватерниона с суффиксом _v, то есть (1,0,0), повернутый на A_q, становится A_v.

Демонстрация

Я реализовал такой сценарий здесь (интерактивный), с источником здесь и также прикрепил gif ниже.

enter image description here

Моя проблема

Моя проблема в том, что когда A_v и B_v близки к противоположным (или кажутся приближающимися к антипараллельным), D_q демонстрирует внезапный поворот / крен, что нежелательно.Изображение выше демонстрирует это.

Код, о котором идет речь

Он находится в C ++ API UE4, но он должен быть достаточно независимым от языка / фреймворка для анализа:

FTransform UMWEUtil::FindNewRotation(FTransform A_t, FVector B_v)
{
    FQuat A_q = A_t.GetRotation();
    FVector A_v = A_q.GetForwardVector();

    A_v.Normalize();
    B_v.Normalize();

    FVector AxisOfRotation = FVector::CrossProduct(A_v, B_v).GetSafeNormal();
    float Rads = FMath::Acos(FVector::DotProduct(A_v, B_v));
    FQuat C_q(AxisOfRotation, Rads);

    FQuat D_q = C_q * A_q;

    return FTransform(D_q);
}

Мои вопросы

  1. Почему возникает этот внезапный артефакт крена / закручивания?
  2. Я предполагаю, что это из-за перекрестного произведения A_v X B_v изменения полушарий.Но тогда, почему это происходит только один раз, а не дважды (видно, что перекрестное произведение, A_v X B_v перемещает полусферы дважды за полный оборот)?
  3. Наконец, решение, которое я нашел, состоит в том, чтобы разложить D_q в кватернионы качания / кручения и используйте только кватернион качания (таким образом, удаляя внезапный поворот).Тем не менее, это похоже на пластырь из-за моего непонимания проблемы, есть ли другое решение, которое приведет к плавному переходу?

Мое решение (может быть, ненужное?)

FTransform UMWEUtil::FindNewRotation2(FTransform A_t, FVector B_v)
{
    FQuat A_q = A_t.GetRotation();
    FVector A_v = A_q.GetForwardVector();

    A_v.Normalize();
    B_v.Normalize();

    FVector AxisOfRotation = FVector::CrossProduct(A_v, B_v).GetSafeNormal();
    float Rads = FMath::Acos(FVector::DotProduct(A_v, B_v));
    FQuat C_q(AxisOfRotation, Rads);

    FQuat D_q = C_q * A_q;

    FQuat OutSwing;
    FQuat OutTwist;

    D_q.ToSwingTwist(FVector::ForwardVector, OutSwing, OutTwist);

    return FTransform(OutSwing);
}
...