2012-12-28 18 views
5

クォータニオンの3Dモデルでアークボールローテーションの簡単な実装を探しています()。具体的には、iOSのGLKitを使用しています。これまでのところ、私は、次のソースを検討している:私もherehereからソースコードと数学を理解しようとしてきたクォータニオンによるアークボールの回転(iOS GLKitを使用)

。オブジェクトを回転させることはできますが、特定の角度でジャンプし続けるので、ジンバルロックが作動していることを恐れています。私はジェスチャー認識機能を使って回転をコントロールしています(パンジェスチャーはロールとヨーに、回転ジェスチャーはピッチに影響を与えます)。私は四元数処理とモデルビュー行列変換のための私のコードを添付しています。

変数:

  • GLKQuaternion rotationE;

クォータニオン処理:

- (void)rotateWithXY:(float)x and:(float)y 
{ 
    const float rate = M_PI/360.0f; 
    GLKVector3 up = GLKVector3Make(0.0f, 1.0f, 0.0f); 
    GLKVector3 right = GLKVector3Make(1.0f, 0.0f, 0.0f); 

    up = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), up); 
    self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(x*rate, up)); 

    right = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), right); 
    self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(y*rate, right)); 
} 

- (void)rotateWithZ:(float)z 
{ 
    GLKVector3 front = GLKVector3Make(0.0f, 0.0f, -1.0f); 

    front = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), front); 
    self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(z, front)); 
} 

モデルビュー行列変換(インサイドはループを描く):

// Get Quaternion Rotation 
GLKVector3 rAxis = GLKQuaternionAxis(self.transformations.rotationE); 
float rAngle = GLKQuaternionAngle(self.transformations.rotationE); 

// Set Modelview Matrix 
GLKMatrix4 modelviewMatrix = GLKMatrix4Identity; 
modelviewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f); 
modelviewMatrix = GLKMatrix4Rotate(modelviewMatrix, rAngle, rAxis.x, rAxis.y, rAxis.z); 
modelviewMatrix = GLKMatrix4Scale(modelviewMatrix, 0.5f, 0.5f, 0.5f); 
glUniformMatrix4fv(self.sunShader.uModelviewMatrix, 1, 0, modelviewMatrix.m); 

どんな助力も大歓迎ですが、できるだけシンプルにしてGLKitに固執したいと思います。

答えて

5

ここではいくつかの問題が発生しているようです。

  1. はあなたがパンする[X、Y]を使用していると言うが、それはあなたがピッチとヨーためにそれらを使用している以上のように見えます。少なくとも、パンニングは回転ではなく平行移動です。

  2. 何かが欠けていない限り、それを更新しようとするたびにローテーション全体を置き換えるようにも見えます。現在の回転の逆数でベクトルを回転させ、そのベクトルとある角度から四元数を作成します。これは元のベクトルから四元数を作成し、それを現在の回転逆数で回転させることと等価であると私は信じています。あなたはq_e'*q_upです。そして、あなたはq_e*q_e'*q_up = q_upを与える現在の回転、とのことを掛けます。現在の回転はキャンセルされます。これはあなたが望むようなものではないようです。

    あなたが本当に軸と角度から新しい四元を作成し、現在の四元数でそれを乗算するだけです。新しいクォータニオンが左にある場合、向きの変更は目の​​ローカルフレームを使用します。新しいクォータニオンが右にある場合、方向の変更はグローバルフレームになります。あなたが望むと思う:

    self.rotationE = 
        GLKQuaternionMultiply( 
        GLKQuaternionMakeWithAngleAndVector3Axis(x*rate, up),self.rotationE); 
    

    3つのすべてのケースについて逆回転でこれを行います。

  3. は私がGLKitを使ったことがないが、マトリックスにクォータニオンから変換するときには、軸の角度を抽出することが珍しくあります。角度がゼロの場合、軸は定義されていません。それはゼロに近いだときは、数値不安定性を持っています。あなたがGLKMatrix4MakeWithQuaternionを使用して、あなたの平行移動行列とスケールマトリックスと結果の行列を乗算する必要があるように見えます:

    GLKMatrix4 modelviewMatrix = 
        GLKMatrix4Multiply(GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f), 
             GLKMatrix4MakeWithQuaternion(self.rotationE)); 
    modelviewMatrix = GLKMatrix4Scale(modelviewMatrix, 0.5f, 0.5f, 0.5f); 
    
+0

ブリリアント答え、それは完全に働きました。これはクォータニオンへの私の最初のベンチャーなので、明確な説明が大変ありがとう - ありがとう!ジェスチャーは「パン」(iOSコンベンション)と名付けられていますが、実際にはモデルの回転を制御していますが、(1)で挙げた点を明確にするために質問を編集しました。 –

3

私は最近、それはので、ここで、この問題の私の結果の実装についてもう少し聞かれましたです!

- (void)rotate:(GLKVector3)r 
{ 
    // Convert degrees to radians for maths calculations 
    r.x = GLKMathDegreesToRadians(r.x); 
    r.y = GLKMathDegreesToRadians(r.y); 
    r.z = GLKMathDegreesToRadians(r.z); 

    // Axis Vectors w/ Direction (x=right, y=up, z=front) 
    // In OpenGL, negative z values go "into" the screen. In GLKit, positive z values go "into" the screen. 
    GLKVector3 right = GLKVector3Make(1.0f, 0.0f, 0.0f); 
    GLKVector3 up = GLKVector3Make(0.0f, 1.0f, 0.0f); 
    GLKVector3 front = GLKVector3Make(0.0f, 0.0f, 1.0f); 

    // Quaternion w/ Angle and Vector 
    // Positive angles are counter-clockwise, so convert to negative for a clockwise rotation 
    GLKQuaternion q = GLKQuaternionIdentity; 
    q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.x, right), q); 
    q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.y, up), q); 
    q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.z, front), q); 

    // ModelView Matrix 
    GLKMatrix4 modelViewMatrix = GLKMatrix4Identity; 
    modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeWithQuaternion(q)); 
} 

はあなたが良いの使用にそれを置くホープ:)

関連する問題