2

我正在尝试使用QuaternionlibGDX 中的 a 来旋转我的相机。我有一个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

我必须评论关于您的代码的两件事:

  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()是乘法?我认为你需要做的不仅仅是一个乘法来进行旋转。这是我用于围绕轴角(四元数)旋转矢量或点的代码:

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 游戏(想想 homeworld)。宇宙飞船有一个direction vector(它们行进的方向),用于在每个滴答声中更新它们的运动并将它们旋转到朝向行进方向(在draw()函数中)。他们还有一个target vector: 在船的位置和它的当前目的地之间。船只能以turningCircle弧度转动一秒钟。因此,在每个刻度更新运动后,我将方向/目标向量的叉积作为旋转轴,并turningCircle作为角度,创建一个四元数。我通过四元数旋转船舶方向矢量以“转动”船舶。

最终的结果是船经过了许多滴答声,以优美的弧线转弯,直到它朝着正确的方向前进。

同样的过程也可以在战斗飞行模拟器中使用,以模拟人工智能飞机的转弯。使用四元数还可以避免“万向节锁定”,这是真正的飞机会遇到的问题!

然而,使用四元数,你的 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 回答