2012-04-27 16 views
2

私はクォータニオンを使って固定小数点を周回するカメラを持っています。問題は、カメラがx軸を中心に回転し、極を通過すると、カメラが反転して鏡像を生成することです。これは、カメラが反対の向きに向いているが、カメラのアップベクトルが変更されていないため意味をなさない。明らかに、新しいアップベクトルは、ルックベクトルと右ベクトルから計算する必要がありますが、私はそれを動作させるように見えることはできません。注:これは、クォータニオンを表すのにhttp://commons.apache.org/math/api-2.2/org/apache/commons/math/geometry/Rotation.htmlを使用します。クォータニオン回転のカメラフリッピングを避けるには?

とにかく、次の基本的な手順でカメラを回転させています。

private Rotation total = Rotation.IDENTITY; 

カメラのアップベクトルは以下のように初期化される:

private Vector3D up = new Vector3D(0, 1, 0); 

回転が行われ

回転四元はアイデンティティ[1、0、0、0]に初期化されますカメラの現在の回転をクォータニオンとして保存し、その後にこのクォータニオンに任意の回転を適用することによって、結合されたクォータニオン(合計)を使用してカメラの位置を回転させる。

@Override 
public void keyPressed(KeyEvent e) { 
    if (e.getKeyCode() == KeyEvent.VK_W) { 
     camera.setAxis(new Vector3D(1, 0, 0)); 
     camera.setRotation(0.1); 
    } 
    if (e.getKeyCode() == KeyEvent.VK_A) { 
     camera.setAxis(new Vector3D(0, 1, 0)); 
     camera.setRotation(0.1); 
    } 
    if (e.getKeyCode() == KeyEvent.VK_S) { 
     camera.setAxis(new Vector3D(1, 0, 0)); 
     camera.setRotation(-0.1); 
    } 
    if (e.getKeyCode() == KeyEvent.VK_D) { 
     camera.setAxis(new Vector3D(0, 1, 0)); 
     camera.setRotation(-0.1); 
    } 
} 

各レンダリングループrotateCamera中:次のようにキーを押すことによって生成される任意の新しい回転軸/角度を記憶

/** 
* Rotates the camera by combining the current rotation (total) with any new axis/angle representation of a new rotation (newAxis, rotation). 
*/ 
public void rotateCamera() { 
    if (rotation != 0) { 
     //Construct quaternion from the new rotation: 
     Rotation local = new Rotation(Math.cos(rotation/2), Math.sin(rotation/2) * newAxis.getX(), Math.sin(rotation/2) * newAxis.getY(), Math.sin(rotation/2) * newAxis.getZ(), true); 

     //Generate new camera rotation quaternion from current rotation quaternion and new rotation quaternion: 
     total = total.applyTo(local); 

     //Rotate the position of the camera using the camera rotation quaternion: 
     cam = rotateVector(local, cam); 

     //rotation is complete so set the next rotation to 0 
     rotation = 0; 
    } 
} 

/** 
* Rotate a vector around a quaternion rotation. 
* 
* @param rotation The quaternion rotation. 
* @param vector A vector to be rotated. 
* @return The rotated vector. 
*/ 
public Vector3D rotateVector(Rotation rotation, Vector3D vector) { 
    //set world centre to origin, i.e. (width/2, height/2, 0) to (0, 0, 0) 
    vector = new Vector3D(vector.getX() - width/2, vector.getY() - height/2, vector.getZ()); 

    //rotate vector 
    vector = rotation.applyTo(vector); 

    //set vector in world coordinates, i.e. (0, 0, 0) to (width/2, height/2, 0) 
    return new Vector3D(vector.getX() + width/2, vector.getY() + height/2, vector.getZ()); 
} 

フィールドnewAxis回転:次のコードは、この手順を説明します()メソッドが呼び出され、次のコードでカメラが設定されます。

glu.gluLookAt(camera.getCam().getX(), camera.getCam().getY(), camera.getCam().getZ(), camera.getView().getX(), camera.getView().getY(), camera.getView().getZ(), 0, 1, 0); 
+3

なぜgluLookAtを使うのか分かりませんが、カメラの位置と見たいものの回転を計算します。回転数を自分で計算している場合は、ビューマトリックスを直接設定しないでください。 – Ishtar

答えて

1

あなたは何か変なことをしています。単位四元数は、全体の方向を表します。あなたは通常それと一緒に 'アップ'ベクトルを使用しません。しかし...クォータニオンからそれを得るのではなく、定数の 'up'ベクトル[0,1,0]を使うだけで、あなたが望む効果を得ることができるようです。

クォータニオンは必要ないようです。あなたが望むのは、[0,1,0]の一定の「上」のベクトルです。次に、あなたが周回しているポイントである「アット」ポイントが必要です。次に、あなたの軌道点との間のベクトルとあなたの「上」ベクトルとの間の外積によって定義される軸のまわり、またはy軸周りに(あなたの軌道点に関して)回転することができる「目」点が必要です「目」の点。

+0

あなたの答えをありがとう。私がこれをやっていた元のやり方は、 glu.gluLookAt(camera.getCam()。getX()、camera.getCam()。getY()、camera.getCam()。getZ()、camera.getView ()。getX()、camera.getView()。getY()、camera.getView()。getZ()、0、1、0); しかし、これはカメラのフリッピングになります。私はクォータニオンがこれを行う適切な方法だと思いました。 Isttarが示唆していると理解しているように、私はglTranslatef()とglMultMatrixfを四元数からの行列と一緒に使うべきですか? – noise

+0

@noiseどのような状況で、カメラのフリッピングが発生しましたか?どのような方法で反転しますか? – JCooper

関連する問題