2012-12-20 57 views
1

我在屏幕左下角有一個2D虛擬操縱桿。我有一個在原點(0,0,0)以3D繪製的球體......我的相機可以圍繞球體運行。我正在嘗試使用操縱桿移動相機,但不知道如何才能做到這一點。我需要從操縱桿創建一個軸角旋轉,並更新使用四元數表示其方向的攝像機角度。以下是我目前有:從2D操縱桿獲取3D旋轉軸和角度

我的相機旋轉存儲爲四元數:

// The current rotation 
public Quaternion rotation = new Quaternion(); 

// The temp quaternion for the new rotation 
private Quaternion newRotation = new Quaternion(); 

旋轉和攝像機通過這些方法更新:

// Update the camera using the current rotation 
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, tmp.set(camera.position).add(camera.direction), camera.up); 

    // Rotate the current view matrix using our rotation quaternion 
    camera.view.rotate(rotation); 

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

public void updateRotation(float axisX, float axisY, float axisZ, float speed) 
{ 
    // Update rotation quaternion 
    newRotation.setFromAxis(Vector3.tmp.set(axisX, axisY, axisZ), ROTATION_SPEED * speed * MathHelper.PIOVER180); 
    rotation.mul(newRotation); 

    // Update the camera 
    update(true); 
} 

我現在打電話updateRotation()像這個:

// Move the camera 
if (joystick.isTouched) 
{ 
    // Here is where I'm having trouble... 
    // Get the current axis of the joystick to rotate around 
    tmpAxis = joystick.getAxis(); 
    axisX = tmpAxis.X; 
    axisY = tmpAxis.Y; 

    // Update the camera with the new axis-angle of rotation 

    // joystick.getSpeed() is just calculating the distance from 
    // the start point to current position of the joystick so that the 
    // rotation will be slower when closer to where it started and faster 
    // as it moves toward its max bounds 

    controller.updateRotation(axisX, axisY, axisZ, joystick.getSpeed()); 
} 

我目前的getAxis()遇到HOD從Joystick類:

public Vector2d getAxis() 
{ 
    Vector2d axis = new Vector2d(0.0f, 0.0f); 
    float xOffset = 0; 
    float yOffset = 0; 
    float angle = getAngle(); 

    // Determine x offset 
    xOffset = 1f; 

    // Determine y offset 
    yOffset = 1f; 

    // Determine positive or negative x offset 
    if (angle > 270 || angle < 90) 
    { 
     // Upper left quadrant 
     axis.X = xOffset; 
    } 
    else 
    { 
     axis.X = -xOffset; 
    } 

    // Determine positive or negative y offset 
    if (angle > 180 && angle < 360) 
    { 
     // Upper left quadrant 
     axis.Y = yOffset; 
    } 
    else 
    { 
     axis.Y = -yOffset; 
    } 

    return axis; 
} 

回答

1

我給你一些提示,思考的問題。可能不是一個完整的答案,但它應該有幫助!

1-真的有必要有一個數學上完美的棒?我的意思是,你可以從中心檢測位移,並從中計算出你的角度。例如,Stick是以[x,y]爲中心,用戶手指在[x + a,y + b],那麼你的旋轉角度可以是func(a),func(b),其中func()是你定義的函數幾乎總是憑經驗)。例如:

angleX = (a/30) % 360; //you should consider maximum displacements may be 

2 - 小心你如何使用你的四元數,

rotation.mul(newRotation); 
rotation.leftMul(newRotation); 

是不等價的。通常,您可以使用第二個選項根據您指定的軸旋轉旋轉的物體,而不管該模型是否已旋轉。這就是你想要做的,如果用戶移動堅持,你旋轉你的相機(你不關心,如果相機已經積累了旋轉)。爲了完成我的「廉價執行」答案,您可以使用Libgdx的setEulerAngles(浮動偏航,浮動俯仰,浮動滾動)輕鬆計算您的quaterion。所以:

newRotation.setEulerAngles(angleX, angleY, 0). 

記得離開復制這個quaterion,所以你得到所有三軸的旋轉!

可能缺少一些細節。可能是你應該在setEulerAngles中切換參數,可能是你的凸輪不會看到正確的位置,但我只是想表明,有時候一個便宜的解決方案是最好的解決方案(因爲它是一個3列的近似值)。至少應該是足夠快的原型!

+0

感謝您的幫助,誰知道這將是如此簡單哈哈......我知道我很近就需要使用'setEulerAngles()'和'leftMul()'並修改我的'getAxis()'方法在「操縱桿」課堂上,瞧! – DRiFTy

2

我只想用3個矢量來定義照相機:位置,向前,向上(右=交叉(向前,向上))。那麼對於你的情況,你一直在尋找向(0,0,0),所以只是這樣的輸入更新這3個向量:

去向上/向下:

right = cross(forward, up); 
posititon = normalized(position + up*(input*zoomFactor)) * length(position); //zoomFactor might be useful if you are looking from close to reduce the move but is optional 
forward = normalized((0,0,0)-position); 
up = cross(right, forward);//should already be normalized Note: might be cross(forward, right) 

轉到左/右:

right = cross(forward, up); 
position = normalized(position + right*(input*zoomFactor)) * length(position); 
forward = normalized((0,0,0)-position); 
right = cross(forward, up); //you do need to update it 
up = cross(right, forward); //Note: might be cross(forward, right) 

傾斜左/右:

up = normalize(up + right*input); //no zoom factor needed here 

放大/縮小:

position = position + forward*input;//in your case you might just want to set it to some percentage: position = position + forward*(length(position) * (input)); 

這種方法應該只適用於小輸入值女巫是通常的情況。相對於輸入的角度改變將是α= atan(輸入),所以如果輸入是無窮大,角度將改變90度。但您可以輕鬆保存/加載狀態,並且您可以手動設置攝像頭位置和伴侶矢量。所以你有一切你需要調用「lookAt」。

+0

我試過了,它允許我移動相機,但它不再在軌道上運行......任何想法?我在我的相機控制器類moveLeft(),moveRight(),moveUp()和moveDown()中創建了4個方法。根據控制桿在x軸和y軸兩側的位置,我只是調用了這些方法。 – DRiFTy

+0

如果它不是在繞軌道運動,它在做什麼?你獲得了什麼樣的運動效果,以及你插入「lookAt」的參數是什麼? –

2

您可能想要根據當前的旋轉狀態更新旋轉,而不是僅在固定的全局軸上旋轉(向上移動&)我的意思是,在開始位置,例如相機朝向(0,0 ,1)矢量:

  • 物體在(0,0,0)
  • 凸輪是在(0,0,-2)
  • 凸輪DIR點(0,0,1)

如果你推動joystic k上一90º,相機應該:

  • 移動到(0,2,0)現在的位置
  • 凸輪DIR點(0,-1,0)

如果你現在推動操縱桿RO右90度,照相機應該是這樣的:

  • 凸輪在pos(2,0,0)
  • 凸輪DIR向量(-1,0,0)

也就是說,您可以通過讓相機處於固定位置並旋轉相機所需的物體來實現此目的。

一個簡單的方法是生成一對四元數,每個軸旋轉一個。但是你想旋轉的軸隨着物體的旋轉而變化。如果攝像機向上旋轉並向下看物體中心,則應將四元數定義爲繞右軸旋轉x度(1,0,0),以便攝像機向上旋轉。一旦物體旋轉使攝像機看起來像是向上,對象「向上」向量不再是全局向上的,而是由先前的四元數旋轉的「全局向上向量」。

方法:

1-對於每一幀通過使用當前對象旋轉而旋轉的全球向上和向右矢量計算局部向上和向右矢量。

2-一旦你有本地向上和向右的矢量,閱讀操縱桿的翻譯量。

3-創建兩個圍繞本地向量旋轉的新四元數。將兩個四元數相乘,結果應該與當前對象四元數相乘(相乘)。

4-將最終四元數轉換爲矩陣並將其用作當前的模型視圖矩陣。

編輯:

使用ShadingZen類(我不使用libGDX)的某些代碼:

class Camera{ 
static Vector3 mRight = new Vector3(1.f, 0.f, 0.f); 
static Vector3 mUp = new Vector3(0.f, 1.f, 0.f); 
static Vector3 mFront = new Vector3(0.f, 0.f, 1.f); // Maybe your front is (0, 0, -1) or (0, 1, 0) 

Vector3 mLocalRight; = new Vector3(1.f, 0.f, 0.f); 
Vector3 mLocalUp = new Vector3(0.f, 1.f, 0.f); 
Vector3 mLocalFront = new Vector3(0.f, 0.f, 1.f); 

Quaternion mRotation = new Quaternion(0.f, 0.f, 0.f, 1.f); // Identity rotation 
Vector3 mCameraInitialPos = ... 

... 

/** 
* Compute local axis vectors given the current camera rotation 
* tickDeltaTime is useful to prevent "jumps" in movement 

*/ 
private void updateRotation(){ 
    // Get local (rotated) vectors (current local axis) 
    mLocalRight = mRotation.mul(mRight); // Rotate mRight using mRotation quaternion 
    mLocalUp = mRotation.mul(mUp); 
    mLocalFront = mRotation.mul(mFront); 

    Quaternion rotationAroundRightAxis = new Quaternion(mLocalRight, mJoystickAmmountY*tickDeltaTime); 
    Quaternion rotationAroundUpAxis = new Quaternion(mLocalUp, mJoystickAmmountX*tickDeltaTime); 

    // Chain rotations 
    mRotation = mRotation.mul(rotationAroundRightAxis.mul(rotationAroundUpAxis)); 

    // Now mRotation contains this step or tick's rotation ammount nad past rotations 
    mCameraPos = mRotation.mul(mCameraInitialPos); 
} 

public void update(boolean updateFrustum) 
{ 
    updateRotation(); 

    float aspect = camera.viewportWidth/camera.viewportHeight; 
    camera.projection.setToProjection(Math.abs(camera.near), Math.abs(camera.far), camera.fieldOfView, aspect); 
    camera.view.setToLookAt(mCameraPos, mLocalFront, mLocalUp); // This probably computes your view matrix 

    // Not sure if libGDX needs this or calculates internally 
    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); 
    } 
} 
} 
+0

我寧願讓相機進入軌道,因爲有很多物體圍繞固定球體運行,這對我來說更有意義......我不太確定如何將我的操縱桿的值應用到我的四元數讓我可以自由地圍繞球體運行。 – DRiFTy

+0

我編輯了一些代碼更新的答案。 – Trax

+0

太棒了,我會試試看!只有一個問題,當你更新旋轉時,你會期待'joystickAmountX'和'joystickAmountY'是什麼?它將分別是從x軸和y軸的0到360之間的旋轉角度嗎?我不太確定我應該傳遞什麼,以及獲得這些值的正確方法是什麼。我非常感謝你的幫助! – DRiFTy