2012-12-15 62 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

添加了一個帶有代碼的示例 –