四元数绕轴旋转的分量

Ben*_*ers 38 rotation quaternions

我很难找到关于这个主题的任何好消息.基本上我想找到四元数旋转的分量,即围绕给定轴(不一定是X,Y或Z - 任意单位矢量).有点像将四元数投影到矢量上.因此,如果我要求围绕与四元数轴平行的某个轴进行旋转,我将得到相同的四元数.如果我要求围绕与四元数轴正交的轴旋转,我会得到一个标识四元数.中间......嗯,这就是我想知道如何解决:)

min*_*gic 28

这个问题有一个优雅的解决方案,特别适合四元数.它被称为"摆动扭曲分解":

在伪代码中

/**
   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();
}
Run Code Online (Sandbox Code Playgroud)

这个代码的长期答案和推导可以在这里找到 http://www.euclideanspace.com/maths/geometry/rotations/for/decomposition/

  • 奇点很容易被捕获,检查“扭曲”长度不为零。它不存在于上面的代码中(为了简化代码)。 (2认同)

seb*_*ebf 18

前几天我试图为动画编辑器找到完全相同的东西; 这是我如何做到的:

  1. 取你想要找到旋转的轴,找到它的正交向量.
  2. 使用四元数旋转此新矢量.
  3. 将此旋转矢量投影到平面上,该平面的法线就是您的轴
  4. 此投影矢量和原始正交的点积的acos是您的角度.

    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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

下面是找到正交函数的代码,但是如果你只想要上述方法的代码,你可以做得更好:

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();
}
Run Code Online (Sandbox Code Playgroud)

虽然上述工作可能会发现它的行为并不像您期望的那样.例如,如果四元数将矢量旋转90度.大约X和90度.在Y周围你会发现,如果你在Z周围分解旋转它将是90度.同样.如果你想象一个矢量进行这些旋转,那么这是完全合理的,但根据你的应用,它可能不是所希望的行为.对于我的应用 - 约束骨骼关节 - 我最终得到了一个混合系统.整个过程中使用的矩阵/量子,但是当涉及约束关节的方法时,我在内部使用了欧拉角,每次都将旋转量子分解为围绕X,Y,Z的旋转.

祝你好运,希望有所帮助.