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);
}
}
私は十分な詳細を提供してきました願っています:以下のように
回転軸と回転角は、簡単なキーを押すことで設定されています。どんな助けも非常に高く評価されるでしょう。
SceneRendererクラスは、render()を呼び出してレンダリングループを呼び出す表示(GLAutoDrawable描画可能)を実装しています。アプリケーションのモデル側は更新イベントを渡すだけで、レンダリングキューに格納されます。ごめんなさい。 Cameraクラスには、すでに目の位置とその見え方が保存されています(コードを元の投稿に追加します)。 上方向を定義するベクトルに関して。これは、カメラの回転に合わせて変更する必要がありますか?私はあなたがアップ方向が変わらないカムの位置を回転させた後にgluLookAt()を使うと仮定しました。 – noise
これは、固定小数点を周回する第三者のカメラであると説明する必要があります。見ているポイントは、回転すると変化しません。カメラが翻訳されていても、それは完全に別のものです。カメラの位置を回転させるだけでは不十分ですか?私がばかげている場合は申し訳ありません。 :) – noise
ああ、そうだ。回転コードはかなり理解しにくいので、最初に行うべきことは適切なベクトル数学ライブラリを使用することです。カメラ内のすべてを実装するのではなく、実際の作業を行う3Dベクトルと四元数のクラスが必要です。現在の状態では、あなたのコードが実際に何をしているのか、それが正しく実行されているのかを言うのはかなり難しいです。 –