Компонент кватернионного вращения вокруг оси - PullRequest
37 голосов
/ 10 сентября 2010

У меня проблемы с поиском полезной информации по этой теме.По сути, я хочу найти компонент кватернионного вращения, который находится вокруг данной оси (не обязательно X, Y или Z - любой произвольный единичный вектор).Вроде как проекция кватерниона на вектор.Поэтому, если бы я попросил вращение вокруг некоторой оси, параллельной оси кватерниона, я бы вывел тот же кватернион обратно.Если бы я попросил вращение вокруг оси, ортогональной оси кватерниона, я бы выбрал кватернион-единицу.И в промежутке ... ну, вот что я хотел бы знать, как работать :)

Ответы [ 3 ]

27 голосов
/ 14 марта 2014

Существует элегантное решение этой проблемы, особенно подходящее для кватернионов. Это известно как "разложение твист колебания":

в псевдокоде

/**
   Decompose the rotation on to 2 parts.
   1. Twist - rotation around the "direction" vector
   2. Swing - rotation around axis that is perpendicular to "direction" vector
   The rotation can be composed back by 
   rotation = swing * twist

   has singularity in case of swing_rotation close to 180 degrees rotation.
   if the input quaternion is of non-unit length, the outputs are non-unit as well
   otherwise, outputs are both unit
*/
inline void swing_twist_decomposition( const xxquaternion& rotation,
                                       const vector3&      direction,
                                       xxquaternion&       swing,
                                       xxquaternion&       twist)
{
    vector3 ra( rotation.x, rotation.y, rotation.z ); // rotation axis
    vector3 p = projection( ra, direction ); // return projection v1 on to v2  (parallel component)
    twist.set( p.x, p.y, p.z, rotation.w );
    twist.normalize();
    swing = rotation * twist.conjugated();
}

А длинный ответ и вывод этого кода можно найти здесь http://www.euclideanspace.com/maths/geometry/rotations/for/decomposition/

17 голосов
/ 03 декабря 2010

Я провел другой день, пытаясь найти то же самое для редактора анимации;вот как я это сделал:

  1. Возьмите ось, вокруг которой хотите найти вращение, и найдите для нее ортогональный вектор.
  2. Поверните этот новый вектор, используя свой кватернион.
  3. Проецируйте этот повернутый вектор на плоскость, нормалью которой является ваша ось
  4. Акос точечного произведения этого спроецированного вектора и исходного ортогонального угла - ваш угол.

    public static float FindQuaternionTwist(Quaternion q, Vector3 axis)
    {
        axis.Normalize();
    
        // Get the plane the axis is a normal of
        Vector3 orthonormal1, orthonormal2;
        ExMath.FindOrthonormals(axis, out orthonormal1, out orthonormal2);
    
        Vector3 transformed = Vector3.Transform(orthonormal1, q);
    
        // Project transformed vector onto plane
        Vector3 flattened = transformed - (Vector3.Dot(transformed, axis) * axis);
        flattened.Normalize();
    
        // Get angle between original vector and projected transform to get angle around normal
        float a = (float)Math.Acos((double)Vector3.Dot(orthonormal1, flattened));
    
        return a;
    }
    

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

private static Matrix OrthoX = Matrix.CreateRotationX(MathHelper.ToRadians(90));
private static Matrix OrthoY = Matrix.CreateRotationY(MathHelper.ToRadians(90));

public static void FindOrthonormals(Vector3 normal, out Vector3 orthonormal1, out Vector3 orthonormal2)
{
    Vector3 w = Vector3.Transform(normal, OrthoX);
    float dot = Vector3.Dot(normal, w);
    if (Math.Abs(dot) > 0.6)
    {
        w = Vector3.Transform(normal, OrthoY);
    }
    w.Normalize();

    orthonormal1 = Vector3.Cross(normal, w);
    orthonormal1.Normalize();
    orthonormal2 = Vector3.Cross(normal, orthonormal1);
    orthonormal2.Normalize();
}

Хотя приведенное выше работаетВы можете обнаружить, что он не ведет себя так, как вы ожидаете.Например, если ваш кватернион поворачивает вектор на 90 градусов.вокруг X и 90 град.вокруг Y вы найдете, если вы разложите вращение вокруг Z, это будет 90 градусов.также.Если вы представляете вектор, совершающий эти вращения, то это имеет смысл, но в зависимости от вашего приложения это может быть нежелательным поведением.Для моего приложения - ограничения скелетных суставов - я получил гибридную систему.Матрицы / кваты использовались повсеместно, но когда дело дошло до метода ограничения соединений, я использовал внутренние углы Эйлера, разлагая кват вращения на повороты вокруг X, Y, Z каждый раз.

Удачи, надеюсь, это помогло.

0 голосов
/ 31 января 2011

Я попытался реализовать ответ Себфа, это кажется хорошим, за исключением того, что выбор вектора на шаге 1:

  1. Возьмите ось, вокруг которой хотите найти вращение, и найдите ортогональный вектор к нему.

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

Спасибо sebf за то, что выбрали правильный курс.

...