0

私は OpenGL と 3D プログラミングにかなり慣れていませんが、http://www.cprogramming.com/tutorial/3d/quaternions.htmlのチュートリアルに基づいてクォータニオンを使用してカメラの回転を実装し始めました。これはすべて、JOGL を使用して Java で記述されています。

この種の質問が非常に多く寄せられることは承知していますが、探し回っていて、機能する解決策が見つからないため、具体的には私のコードに問題がある可能性があると考えました.

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

回転を自動化すると (左に 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は、永久クォータニオンから生成された回転行列でポイントを乗算するだけです。

回転軸と回転角度は、次のようにキーを押すだけで設定できます。

    @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);
    }
}

十分な詳細を提供できたことを願っています。どんな助けでも大歓迎です。

4

1 に答える 1

1

ジッターについて: コードにレンダー ループは見当たりません。render メソッドはどのようにトリガーされますか? タイマーまたはイベントによって?

2 つの軸を中心に回転するときの混乱した回転は、おそらく、最初の軸の合計回転とともに 2 番目の回転の軸を回転させる必要があるという事実に関連しています。グローバル座標系の X 軸または Y 軸を中心とした回転だけを適用することはできません。カメラの上軸と右軸を中心に回転を適用する必要があります。

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

于 2012-04-26T08:54:51.687 に答える