2012-04-26 45 views
0

OpenGLと3Dプログラミングはかなり新しくなっていますが、私はhttp://www.cprogramming.com/tutorial/3d/quaternions.htmlのチュートリアルに基づいてクォータニオンを使ってカメラの回転を実装しました。これはすべてJOGLを使ってJavaで書かれています。OpenGLでの3Dカメラの回転:カメラのジッタを防ぐには?

私はこれらの種類の質問がかなりたくさん聞かれることを知っていますが、私は周りを探索していますし、解決策を見つけることができないので、私のコードで問題があるかもしれないと考えました。

したがって、問題は、1つ以上の軸で2つの異なる連続回転を行うと、ジッタと奇数回転が発生することです。 1つの軸に沿った最初の回転は、負または正のいずれかで正常に動作します。しかし、ある軸に沿って正に回転し、その軸で負に回転すると、回転が正と負の回転を交互にしているかのように前後にジッタが発生します。

回転を自動化すると(たとえば、左に500回回転してから右に500回回転すると)、正常に動作しているように見え、これがキーの押下に関連していると思うようになりました。しかし、x軸を中心に回転し、その後y軸の周りを回転させると、回転が不正確になります(単語がないため)。とにかく

、私は `シーンノードを描画するための次の表示ループを有するレンダラクラスを持って次のよう

private void render(GLAutoDrawable drawable) { 
    GL2 gl = drawable.getGL().getGL2(); 
    gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); 

    gl.glMatrixMode(GL2.GL_PROJECTION); 
    gl.glLoadIdentity(); 
    glu.gluPerspective(70, Constants.viewWidth/Constants.viewHeight, 0.1, 30000); 
    gl.glScalef(1.0f, -1.0f, 1.0f); //flip the y axis 

    gl.glMatrixMode(GL2.GL_MODELVIEW); 
    gl.glLoadIdentity(); 

    camera.rotateCamera(); 
    glu.gluLookAt(camera.getCamX(), camera.getCamY(), camera.getCamZ(), camera.getViewX(), camera.getViewY(), camera.getViewZ(), 0, 1, 0); 
    drawSceneNodes(gl); 
} 

private void drawSceneNodes(GL2 gl) { 
    if (currentEvent != null) { 
     ArrayList<SceneNode> sceneNodes = currentEvent.getSceneNodes(); 
     for (SceneNode sceneNode : sceneNodes) { 
      sceneNode.update(gl); 
     } 
    } 

    if (renderQueue.size() > 0) { 
     currentEvent = renderQueue.remove(0); 
    } 
} 

回転は、カメラのクラスで行われる:

public class Camera { 
    private double width; 
    private double height; 
    private double rotation = 0; 

    private Vector3D cam = new Vector3D(0, 0, 0); 
    private Vector3D view = new Vector3D(0, 0, 0); 
    private Vector3D axis = new Vector3D(0, 0, 0); 

    private Rotation total = new Rotation(0, 0, 0, 1, true); 

    public Camera(GL2 gl, Vector3D cam, Vector3D view, int width, int height) { 
     this.cam = cam; 
     this.view = view; 
     this.width = width; 
     this.height = height; 
    } 

    public void rotateCamera() { 
     if (rotation != 0) { 
      //generate local quaternion from new axis and new rotation 
      Rotation local = new Rotation(Math.cos(rotation/2), Math.sin(rotation/2 * axis.getX()), Math.sin(rotation/2 * axis.getY()), Math.sin(rotation/2 * axis.getZ()), true); 

      //multiply local quaternion and total quaternion 
      total = total.applyTo(local); 

      //rotate the position of the camera with the new total quaternion 
      cam = rotatePoint(cam); 

      //set next rotation to 0 
      rotation = 0; 
     } 
    } 

    public Vector3D rotatePoint(Vector3D point) { 
     //set world centre to origin, i.e. (width/2, height/2, 0) to (0, 0, 0) 
     point = new Vector3D(point.getX() - width/2, point.getY() - height/2, point.getZ()); 

     //rotate point 
     point = total.applyTo(point); 

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

    public void setAxis(Vector3D axis) { 
     this.axis = axis; 
    } 

    public void setRotation(double rotation) { 
     this.rotation = rotation; 
    } 
} 

方法rotateCamera rotatePointメソッドは、永久四元数から生成された回転行列をポイントに単に乗算するだけでなく、新しい回転と以前の回転から新しいPermanant四元数を生成します。

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

私は十分な詳細を提供してきました願っています:以下のように

回転軸と回転角は、簡単なキーを押すことで設定されています。どんな助けも非常に高く評価されるでしょう。

答えて

1

ジッタについて:コードにレンダリングループが表示されません。レンダリングメソッドはどのようにトリガされますか?タイマーやイベントで?

2軸を回転させたときの回転の乱れは、おそらく、第1の軸の全回転とともに第2の回転の軸を回転させる必要があるという事実に関係していると考えられます。グローバル座標系のX軸またはY軸の周りに回転を適用することはできません。カメラの上軸と右軸について回転を適用する必要があります。

カメラの上方向、右方向、およびビュー方向ベクトルを格納し、それらの軸に回転を直接適用するカメラクラスを作成することをお勧めします。これがFPSのようなカメラの場合は、アップベクトルではなく、絶対Y軸についてカメラを左右に回転させたいと思うでしょう。これにより、カメラの新しい右軸が得られます。次に、新しい右軸を中心にカメラを垂直(上/下を見ながら)に回転させます。ただし、カメラが直接上下に見える場合は注意が必要です。この場合、ビュー方向と上方向ベクトルの外積を使用して右ベクトルを取得することはできません。

+0

SceneRendererクラスは、render()を呼び出してレンダリングループを呼び出す表示(GLAutoDrawable描画可能)を実装しています。アプリケーションのモデル側は更新イベントを渡すだけで、レンダリングキューに格納されます。ごめんなさい。 Cameraクラスには、すでに目の位置とその見え方が保存されています(コードを元の投稿に追加します)。 上方向を定義するベクトルに関して。これは、カメラの回転に合わせて変更する必要がありますか?私はあなたがアップ方向が変わらないカムの位置を回転させた後にgluLookAt()を使うと仮定しました。 – noise

+0

これは、固定小数点を周回する第三者のカメラであると説明する必要があります。見ているポイントは、回転すると変化しません。カメラが翻訳されていても、それは完全に別のものです。カメラの位置を回転させるだけでは不十分ですか?私がばかげている場合は申し訳ありません。 :) – noise

+0

ああ、そうだ。回転コードはかなり理解しにくいので、最初に行うべきことは適切なベクトル数学ライブラリを使用することです。カメラ内のすべてを実装するのではなく、実際の作業を行う3Dベクトルと四元数のクラスが必要です。現在の状態では、あなたのコードが実際に何をしているのか、それが正しく実行されているのかを言うのはかなり難しいです。 –

関連する問題