Pertanyaan Komponen rotasi quaternion di sekitar sumbu


Saya mengalami kesulitan menemukan informasi yang bagus tentang topik ini. Pada dasarnya saya ingin mencari komponen dari rotasi quaternion, yaitu sekitar sumbu yang diberikan (tidak harus X, Y atau Z - sembarang vektor unit). Semacam seperti memproyeksikan quaternion ke vektor. Jadi jika saya meminta rotasi di sekitar beberapa sumbu sejajar dengan sumbu keempat, saya akan mendapatkan quaternion yang sama kembali. Jika saya harus meminta rotasi di sekitar sumbu orthogonal ke sumbu quaternion, saya akan mendapatkan quaternion identitas. Dan di antara ... yah, itulah yang saya ingin tahu bagaimana cara kerjanya :)


32
2017-09-10 11:34


asal


Jawaban:


Saya menghabiskan hari yang lain mencoba menemukan hal yang sama persis untuk editor animasi; di sini adalah bagaimana saya melakukannya:

  1. Ambillah sumbu yang ingin Anda temukan putarannya, dan temukan vektor ortogonal padanya.
  2. Putar vektor baru ini menggunakan quaternion Anda.
  3. Proyeksikan vektor yang dirotasi ini ke pesawat yang normalnya adalah sumbu Anda
  4. The acos dari produk titik vektor yang diproyeksikan ini dan orthogonal asli adalah sudut Anda.

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

Berikut adalah kode untuk menemukan orthonormals namun Anda mungkin bisa melakukan lebih baik jika Anda hanya ingin yang untuk metode di atas:

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

Meskipun hal-hal di atas berhasil, Anda mungkin merasa tidak berperilaku seperti yang Anda harapkan. Misalnya, jika quaternion Anda memutar vektor 90 derajat. sekitar X dan 90 derajat. sekitar Y Anda akan menemukan jika Anda menguraikan rotasi sekitar Z akan 90 deg. demikian juga. Jika Anda membayangkan sebuah vektor yang membuat rotasi ini maka ini masuk akal tetapi tergantung pada aplikasi Anda mungkin tidak diinginkan perilaku. Untuk aplikasi saya - membatasi sendi kerangka - saya berakhir dengan sistem hibrida. Matriks / Quat digunakan di seluruh tetapi ketika sampai pada metode untuk membatasi sambungan, saya menggunakan sudut euler secara internal, menguraikan quat rotasi ke rotasi sekitar X, Y, Z setiap kali.

Semoga beruntung, Harapan itu membantu.


15
2017-12-03 00:42



Ada solusi elegan untuk masalah ini, khusus cocok untuk quaternions. Hal ini dikenal sebagai "dekomposisi putaran ayunan":

dalam pseudocode

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

Dan jawaban dan derivasi panjang kode ini dapat ditemukan di sini http://www.euclideanspace.com/maths/geometry/rotations/for/decomposition/


23
2018-03-14 09:39



Saya mencoba menerapkan jawaban sebf, sepertinya bagus, kecuali pilihan pilihan vektor di langkah 1:

  1. Ambil sumbu yang ingin Anda temukan putarannya, dan cari   vektor orthogonal untuk itu.

tidak cukup untuk hasil yang berulang. Saya telah mengembangkan ini di atas kertas, dan saya menyarankan tindakan tindakan berikut untuk pilihan vektor ortogonal ke "poros yang ingin Anda temukan rotasi di sekitar", yaitu sumbu pengamatan. Ada pesawat ortogonal terhadap sumbu pengamatan. Anda harus memproyeksikan poros rotasi quaternion Anda ke pesawat ini. Menggunakan vektor yang dihasilkan ini sebagai vektor ortogonal terhadap sumbu observasi akan memberikan hasil yang baik.

Terima kasih kepada sebf karena telah menempatkan saya di jalur yang benar.


0
2018-01-31 11:49