2012-12-15 86 views
2

我正在尝试使用libGDX中的Quaternion来旋转相机。我有一个Quaternion创建和操纵,但我不知道如何将它应用于相机,我试过的一切都没有移动相机。将四元数应用于libGDX中的相机

这里是我设置了旋转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); 
     } 
    } 

回答

2

我必须注释你的代码两件事情:

  1. 到setToLookAt呼叫前不能修改视图矩阵, 这没用,因为该方法重新计算孔矩阵。
  2. 更新()中的第一对几行很浪费。避免 创建不需要的对象(特别是如果您计划在每个周期更新您的 相机)。要将旋转应用于矩阵,您可以调用[矩阵] .rotate(四元数) 。

最后,有很多方法可以旋转你的相机,所以我不能真正解决你的问题,但如果你想看到旋转的东西,只需在相机后面调用camera.view.rotate(rotation)即可。 view.setToLookat。也许你应该旋转别的东西(例如方向矢量,向上矢量等),但是你可以从这开始:

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

快乐编码!

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游戏的例子设置在太空中(想家园)。宇宙飞船有一个direction vector(它们正在旅行的方向),用于每嘀次更新它们的移动并旋转它们以面对行驶方向(在draw()函数中)。他们也有一个target vector:位于船的位置和当前目的地之间。该船只能以每秒turningCircle弧度转弯。所以在更新动作每个刻度之后,我将方向/目标向量的叉积转换为旋转轴,并以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设置为玩家/相机位置,目标作为目标对象,并将角度旋转角度/您希望相机转多快。在draw()你只想用lookAt(directionVector.mX + currentPosition.mX, directionVector.mY + currentPosition.mY, directionVector.mZ + currentPosition.mZ)

+0

很酷,我想我可能会扩展它们的'Quaternion'类来添加更多的功能。我不相信有一个旋转的方法,所以这可能是非常有用的! ...你有什么建议,我应该如何更新相机与四元数旋转后已应用到它? –

+0

如果您使用相机的x,y,z坐标作为RotateVector()中的参数,那么将在输出数组中放入相机的新xyz位置,该位置已经按照四元数轴的指定进行了旋转,该轴固定在原点。如果你从原点到四元数的x,y,z画一条线,这将帮助你形象化你将要旋转的轴...在我自己的引擎中,我不会移动相机,我只是将变换应用到场景中的对象上,使它们位于正确的位置,使它们移动,转向等。 –

+0

添加了一个带有代码的示例 –