2

QuaternionlibGDXでを使用してカメラを回転させようとしています。私はQuaternion作成して操作していますが、それをカメラに適用する方法がわかりません。試したすべてのことで、カメラはまったく動かされませんでした。

これが私が回転を設定する方法ですQuaternion

    public void rotateX(float amount) {
        tempQuat.set(tempVector.set(1.0f, 0.0f, 0.0f), amount * MathHelper.PIOVER180);
        rotation = rotation.mul(tempQuat);
    }

    public void rotateY(float amount) {
        tempQuat.set(tempVector.set(0.0f, 1.0f, 0.0f), amount * MathHelper.PIOVER180);
        rotation = tempQuat.mul(rotation);
    }

これが私がカメラを更新しようとしている方法です(元のlibGDXバージョンと同じ更新方法ですが、回転行列に関する部分を上部に追加しました):

    public void update(boolean updateFrustum) {
        float[] matrix = new float[16];
        rotation.toMatrix(matrix);
        Matrix4 m = new Matrix4();
        m.set(matrix);

        camera.view.mul(m);
        //camera.direction.mul(m).nor();
        //camera.up.mul(m).nor();

        float aspect = camera.viewportWidth / camera.viewportHeight;
        camera.projection.setToProjection(Math.abs(camera.near), Math.abs(camera.far), camera.fieldOfView, aspect);
        camera.view.setToLookAt(camera.position, tempVector.set(camera.position).add(camera.direction), camera.up);
        camera.combined.set(camera.projection);
        Matrix4.mul(camera.combined.val, camera.view.val);

        if (updateFrustum) {
            camera.invProjectionView.set(camera.combined);
            Matrix4.inv(camera.invProjectionView.val);
            camera.frustum.update(camera.invProjectionView);
        }
    }
4

2 に答える 2

2

私はあなたのコードについて2つのことをコメントしなければなりません:

  1. setToLookAtを呼び出す前にビューマトリックスを変更することはできません。そのメソッドはホールマトリックスを再計算するため、役に立ちません。
  2. update()の最初の数行はかなり無駄です。不必要なオブジェクトを作成することは避けてください(特に、カメラをサイクルごとに更新する場合)。回転を行列に適用するには、[matrix] .rotate(quaternion)を呼び出すだけです。

最後に、カメラを回転させる方法はたくさんあるので、私はあなたの問題を本当に解決することはできませんが、何かが回転するのを見たい場合は、camera.view.setToLookatの後にcamera.view.rotate(rotation)を呼び出してください。他の何か(たとえば、方向ベクトル、上向きベクトルなど)を回転させる必要があるかもしれませんが、これから始めることができます。

//protected float[] matrix = new float[16];//unused!

public void update(boolean updateFrustum) {

        float aspect = camera.viewportWidth / camera.viewportHeight;
        camera.projection.setToProjection(Math.abs(camera.near), Math.abs(camera.far), camera.fieldOfView, aspect);
        camera.view.setToLookAt(camera.position, tempVector.set(camera.position).add(camera.direction), camera.up);

        camera.view.rotate(q); // THIS IS THE ONLY REAL CHANGE TO YOUR CODE!

        camera.combined.set(camera.projection);
        Matrix4.mul(camera.combined.val, camera.view.val);

        if (updateFrustum) {
            camera.invProjectionView.set(camera.combined);
            Matrix4.inv(camera.invProjectionView.val);
            camera.frustum.update(camera.invProjectionView);
        }
    }

ハッピーコーディング!

于 2012-12-19T03:12:35.050 に答える
1

Quaternion.mul()掛け算だと思いますか?回転を行うには、1回以上の乗算を行う必要があると思います。ベクトルまたは点を軸角度(クォータニオン)を中心に回転させるために使用するコードは次のとおりです。

private double[] vecQuat = new double[4];
private double[] resQuat = new double[4];
private double[] thisQuat = new double[4];

private double[] conj = new double[4];

/**
 * Rotates a vector (or point) around this axis-angle
 * 
 * @param vectorX the x component of the vector (or point)
 * @param vectorY the y component of the vector (or point)
 * @param vectorZ the z component of the vector (or point)
 * @param outputArray the array in which the results will be stored
 */
public void RotateVector(double vectorX, double vectorY, double vectorZ, double[] outputArray){

    vecQuat[0] = 0.0f;
    vecQuat[1] = vectorX;
    vecQuat[2] = vectorY;
    vecQuat[3] = vectorZ;

    thisQuat[0] = w;
    thisQuat[1] = x;
    thisQuat[2] = y;
    thisQuat[3] = z;

    getConjugate(conj);
    Multiply(vecQuat,conj,resQuat);
    Multiply(thisQuat,resQuat,vecQuat);

    outputArray[0] = vecQuat[1];
    outputArray[1] = vecQuat[2];
    outputArray[2] = vecQuat[3];

}

public void getConjugate(double[] outputArray){

    outputArray[0] = w;
    outputArray[1] = -x;
    outputArray[2] = -y;
    outputArray[3] = -z;

}

public void Multiply(double[] aq, double[] rq, double[] outputArray){

    outputArray[0] = aq[0] * rq[0] - aq[1] * rq[1] - aq[2] * rq[2] - aq[3] * rq[3];
    outputArray[1] = aq[0] * rq[1] + aq[1] * rq[0] + aq[2] * rq[3] - aq[3] * rq[2];
    outputArray[2] = aq[0] * rq[2] + aq[2] * rq[0] + aq[3] * rq[1] - aq[1] * rq[3];
    outputArray[3] = aq[0] * rq[3] + aq[3] * rq[0] + aq[1] * rq[2] - aq[2] * rq[1];

}

libgdxはわかりませんが、上記のような回転機能があるかどうかを確認してください。そうでない場合は、おそらくそれを追加することができます


編集:

カメラで何をしたいのか正確にはわかりませんが、宇宙を舞台にしたRTSゲームにクォータニオンを使用する例を次に示します(故郷を考えてみてください)。宇宙船にはdirection vector(進行方向)があり、ティックごとに移動を更新し、移動方向(draw()関数内)に向けて回転させるために使用されます。またtarget vector、船の位置と現在の目的地の間に:があります。turningCircle船は1秒あたりラジアンでしか向きを変えることができません。したがって、ティックごとに動きを更新した後、方向/ターゲットベクトルの外積を取得して回転軸を取得turningCircleし、角度として取得して、クォータニオンを作成します。船の方向ベクトルをクォータニオンで回転させて、船を「回転」させます。

最終的な結果は、船が何ティックにもわたって、正しい方向に向かうまで優雅な弧を描いて曲がることです。

同じプロセスを戦闘飛行シミュレーターで使用して、AI航空機の旋回をシミュレートすることもできます。クォータニオンを使用すると、実際の航空機が苦しむ「ジンバルロック」も回避できます。

ただし、クォータニオンを使用すると、AI航空機は半分の時間だけ逆さまに飛行する方が便利な場合があるため、機体の軸(つまり、z軸)に沿って飛行機をさらにゆっくりと回転させる必要があります。パイロットが自分自身を「上」に向けていることをシミュレートします。これは、実際には、前方(方向)ベクトルに対して直角に上下のベクトルを追加するだけで、かなり簡単に実行できます。

コードは次のとおりです(アップベクタービットの方向付けを除く):

/**
 * The current position of the spaceship
 */
private Vertex3D currentPosition;

/**
 * The target position of the spaceship
 */
private Vertex3D targetPosition;

/**
 * The current direction in which the spaceship is travelling
 */
private Vector directionVector;

/**
 * The vector towards which the spaceship is turning
 */
private Vector targetVector;

/**
 * The right orientation vector
 */
private Vector rightOrientationVector;

/**
 * The up orientation vector
 */
private Vector upOrientationVector;

/**
 * Angle in radians by which directionVector turns towards TargetVector every tick
 */
private double turningCircle = 0.05f;

public Spaceship(Vertex3D target){

    currentPosition = new Vertex3D(0,0,0);

    // right hand coordinate system: ship is facing "away" from the camera
    directionVector = new Vector(currentPosition, 0,0,-1);
    rightOrientationVector = new Vector(currentPosition, 1,0,0);
    upOrientationVector = new Vector(currentPosition, 0,1,0);

    targetPosition = target;

}

    protected void tick(){
        incrementPosition();
        turn();
        draw();
    }


    protected void incrementPosition(){

        // get movement
        double velocity = getVelocity();

        // move
        currentPosition.mX(currentPosition.mX + directionVector.mX * velocity);
        currentPosition.mY(currentPosition.mY + directionVector.mY * velocity);
        currentPosition.mZ(currentPosition.mZ + directionVector.mZ * velocity);
    }


    private double[] cross = new double[3];
    private double[] newDir = new double[3];
    private Quaternion quat;

    protected void turn(){

        // update target vector relative to new position
        setTargetVector();

        // turn direction vector towards target vector
        MathsExtras.crossProduct(directionVector.mX, directionVector.mY, directionVector.mZ, targetVector.mX, targetVector.mY, targetVector.mZ, cross); 

        quat = new Quaternion(cross[0], cross[1], cross[2], turningCircle);

        quat.RotateVector(directionVector.mX, directionVector.mY, directionVector.mZ, newDir); 

        directionVector.mX = newDir[0];
        directionVector.mY = newDir[1];
        directionVector.mZ = newDir[2];

        direction.normalise();


        // update right orientation
        MathsExtras.crossProduct(direction.mX, direction.mY, direction.mZ, upOrientationVector.mX, upOrientationVector.mY, upOrientationVector.mZ, cross);

        rightOrientationVector.mX = cross[0];
        rightOrientationVector.mY = cross[1];
        rightOrientationVector.mZ = cross[2];

        rightOrientationVector.normalise();

        // update up orientation
        MathsExtras.crossProduct(rightOrientationVector.mX, rightOrientationVector.mY, rightOrientationVector.mZ, direction.mX, direction.mY, direction.mZ, cross);

        upOrientationVector.mX = cross[0];
        upOrientationVector.mY = cross[1];
        upOrientationVector.mZ = cross[2];

        upOrientationVector.normalise();

    }

    protected void setTargetVector(){
        targetVector.mX = targetPosition.getmX() - currentPosition.getmX();
        targetVector.mY = targetPosition.getmY() - currentPosition.getmY();
        targetVector.mZ = targetPosition.getmZ() - currentPosition.getmZ();
        targetVector.normalise();
    }

したがって、同じコードを使用して、カメラを回転させてファーストパーソンシューティングゲームのオブジェクトを見る場合は、方向ベクトルをプレーヤーが見ている方向として設定し、currentPositionをプレーヤー/カメラの位置として設定できます。 、ターゲットオブジェクトとしてのターゲット、および角度/カメラを回転させる速度のturningCirlce。あなたはdraw()ただ使うでしょうlookAt(directionVector.mX + currentPosition.mX, directionVector.mY + currentPosition.mY, directionVector.mZ + currentPosition.mZ)

于 2012-12-16T19:29:07.510 に答える