Pregunta Componente de una rotación de cuaternión alrededor de un eje


Tengo problemas para encontrar buena información sobre este tema. Básicamente, quiero encontrar el componente de una rotación de cuaternión, es decir, alrededor de un eje dado (no necesariamente X, Y o Z, cualquier vector de unidad arbitraria). Algo así como proyectar un cuaternión en un vector. Entonces, si tuviera que pedir la rotación alrededor de un eje paralelo al eje del cuaternión, obtendría el mismo cuaternión. Si tuviera que pedir la rotación alrededor de un eje ortogonal al eje del cuaternión, obtendría un cuaternión de identidad. Y en el medio ... bueno, eso es lo que me gustaría saber cómo solucionarlo :)


32
2017-09-10 11:34


origen


Respuestas:


Pasé el otro día tratando de encontrar exactamente lo mismo para un editor de animación; así es como lo hice:

  1. Tome el eje en el que desea encontrar la rotación y encuentre un vector ortogonal.
  2. Gira este nuevo vector usando tu cuaternión.
  3. Proyecte este vector girado en el plano cuya normal es su eje
  4. El acos del producto de punto de este vector proyectado y el original ortogonal es su ángulo.

    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;
    }
    

Aquí está el código para encontrar los ortonormales, sin embargo, probablemente pueda hacerlo mucho mejor si solo quiere uno para el método anterior:

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();
}

Aunque las obras anteriores pueden parecer que no se comportan como es de esperar. Por ejemplo, si su cuaternión gira un vector 90 grados. alrededor de X y 90 grados. alrededor de Y, encontrará que si descompone la rotación alrededor de Z, será de 90 grados. también. Si imagina un vector haciendo estas rotaciones, entonces tiene mucho sentido, pero dependiendo de su aplicación, puede no ser el comportamiento deseado. Para mi aplicación, restringir las articulaciones esqueléticas, terminé con un sistema híbrido. Matrices / Quats utilizados en todas partes, pero en lo que respecta al método para restringir las uniones utilicé ángulos de euler internamente, descomponiendo la rotación quat en rotaciones alrededor de X, Y, Z cada vez.

Buena suerte, espero que haya ayudado.


15
2017-12-03 00:42



Hay una solución elegante para este problema, especialmente adecuada para cuaterniones. Se conoce como la "descomposición de giro de giro":

en pseudocódigo

/**
   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();
}

Y la respuesta larga y derivación de este código se puede encontrar aquí http://www.euclideanspace.com/maths/geometry/rotations/for/decomposition/


23
2018-03-14 09:39



Traté de implementar la respuesta de Sebf, parece bueno, excepto que la elección de la elección del vector en el paso 1:

  1. Tome el eje en el que desea encontrar la rotación, y encuentre un   vector ortogonal a ella.

no es suficiente para resultados repetibles. Lo he desarrollado en papel, y sugiero el siguiente curso de acción para la elección del vector ortogonal al "eje sobre el que desea encontrar la rotación", es decir, eje de observación. Hay un plano ortogonal al eje de observación. Tienes que proyectar el eje de rotación de tu cuaternión en este plano. Usar este vector resultante como vector ortogonal al eje de observación dará buenos resultados.

Gracias a Sebf por establecerme en el camino correcto.


0
2018-01-31 11:49