3

Opengl でキャラクターを表示し、クォータニオンを使用して軸を中心に回転させます。達成したいのは、それらを独自の軸を中心に回転させることですが、クォータニオンを使用する場合、1 つの軸に従ってオブジェクトを回転させると、他のオブジェクトは取り込まれませんこの回転は固定ワールド軸を中心に回転することを考慮してください。Quaternion Qaccumulative (元の回転) と 3 つの角度の AngleX、AngleY、AngleZ が与えられます。最初に、オイラーの回転が試すべきだと思い、いくつかの手法を試しました:

Quaternion rot1;
Quaternion rot2;
Quaternion rot3;
Vector3 axis ;
float angle;
QAccumulative.getAxisAngle(&axis, &angle);

// first try : around fix axes
    cout << "axis : " << axis << endl;
    rot1.FromAxis(Vector3(1.0,0.0,0.0),angleX);
    rot2.FromAxis(Vector3(0.0,1.0,0.0),angleY);
    rot3.FromAxis(Vector3(0.0,0.0,1.0),angleZ);
    QAccumulative = QAccumulative * rot1;
    QAccumulative = QAccumulative * rot2;
    QAccumulative = QAccumulative * rot3;


/*
// second try, around current modified axes
    rot1.FromAxis(Vector3(axis.x,0.0,0.0),angleX);
    rot2.FromAxis(Vector3(0.0,axis.y,0.0),angleY);
    rot3.FromAxis(Vector3(0.0,0.0,axis.z),angleZ);
    QAccumulative = QAccumulative * rot1;
    QAccumulative = QAccumulative * rot2;
    QAccumulative = QAccumulative * rot3;

*/
/*
// third try with Euler rotation
    Quaternion rotation;
    rotation.FromEuler(10*angleX,10*angleY,10*angleZ);
    QAccumulative = QAccumulative * rotation;
*/
    QAccumulative.normalise();

これまでのところ、それらのどれも機能していません...ローテーションの実装が問題だとは思いませんが、誰かが問題を抱えている場合は、コードを投稿します。オイラーは私が思っていたものではありませんか?目標を達成するためにどの回転缶を使用すればよいですか?

編集:投稿で提案された、これを試しました:

rotate(float angleX,float angleY,float angleZ) {
    Vector3 axis = Vector3(angleX,angleY,angleZ);
    Vector3 worldAxis = QAccumulative * axis;  
    Quaternion worldRotation( worldAxis.x,worldAxis.y,worldAxis.z, 10 );        
    QAccumulative = worldRotation * QAccumulative;
    QAccumulative.normalise();

キャラクターは引き続き固定軸を中心に回転します。

編集:投稿で指定された疑似コードを適用したところ、機能しました:

rotate(float angleX,float angleY,float angleZ) {
    Vector3 axis = Vector3(angleX,angleY,angleZ);
    Vector3 worldAxis = QAccumulative * axis;  
    Quaternion worldRotationx( 1.0,0,0, angleZ );    
    Quaternion worldRotationy( 0,1.0,0, angleX);        
    Quaternion worldRotationz( 0,0,1.0, -angleY );        
    QAccumulative = worldRotationx * worldRotationy * worldRotationz * QAccumulative;
    QAccumulative.normalise();
4

1 に答える 1

2

私の最初の提案は、オイラー角を使用してクォータニオン回転を定義しないことです。

私ができるよりもよく説明するいくつかのリンクを次に示します。

http://bitsquid.blogspot.ca/2013/03/what-is-gimbal-lock-and-why-do-we-still.html

https://mathoverflow.net/questions/95902/the-gimbal-lock-shows-up-in-my-quaternions

http://answers.unity3d.com/questions/573035/voiding-gimbal-lock.html

回転を単一の軸と角度として定義し、それに従うようにクラス インターフェイスを作成することをお勧めします。以下にいくつかの提案を示します。

Vector3 operator* ( const Vector3& vec ) const;        // rotate a vector
Quaternion operator* ( const Quaternion& quat ) const; // concatenate 
void set( const Vector3& axis, float angle );          // set quaternion
void getAxisAngle( Vector3* axis, float* angle );      // extract axis and angle

クォータニオンを使用してローカル軸の回転を適用する場合は、ローカル軸をワールド空間に変換し、その方法で変換を適用するだけです。

文字変換を回転クォータニオン、並進ベクトル、およびスケール ベクトル/スカラーとして保存すると仮定しています。この場合、キャラクターの回転クォータニオンをローカル軸に適用してワールド空間に移動し、そのワールド空間軸を使用して通常どおりに回転を構築および適用します。

キャラクターの現在の回転をクォータニオンとして保存しています。

Quaternion characterQuaternion;

次に、適用するローカル回転があります。

Vector3 localAxis;
float angle;

ローカル軸をワールド空間に変換し、そこからクォータニオンを構築して、キャラクターのクォータニオンに適用する必要があります。

Vector3 worldAxis = characterQuaternion * localAxis;       // transform local axis to world coordinate system   
Quaternion worldRotation( worldAxis, angle );              // build quaternion   
characterQuaternion = worldRotation * characterQuaternion; // apply the rotation

たとえば、キャラクターに 45 単位の角度 (回転方法に応じて度またはラジアン) の「ロール」回転を適用する場合:

ここに画像の説明を入力

localAxis = Vector3(1,0,0);
angle = 45;
于 2014-07-10T18:19:53.230 に答える