給定一個四元數相機,當玩家可以在不同的表面法線(牆)上行走時,該如何計算其旋轉角度。如何在使用四元數相機時計算旋轉角度?
我正在製作一款遊戲,允許玩家在3D空間中的天花板和牆壁上行走。我選擇使用四元數鏡頭系統來避免Gimbal Lock。給定一組up(0,1,0),right(1,0,0)和forward(0,0,1)向量,我構造一個四元數。玩家圍繞朝向旋轉向上矢量,圍繞右向量圍繞俯仰旋轉。
在不改變重力矢量的情況下,相機可以正常工作,並允許玩家在環境中移動,就好像它是標準的FPS遊戲。
爲了簡單起見,我們假設玩家可以按下一個按鍵,該按鍵從與當前法線不同的最近碰撞表面捕捉法線,並將其指定爲新的重力矢量。
不幸的是,我遇到了一個腦袋,並無法弄清楚如何從這個新的重力矢量正確地獲取新的向上,向右和向前的矢量,並將它們應用到當前的旋轉四元數,或者即使這是解決問題的正確方法。如果有幫助,我的相機的移動和旋轉代碼如下。
Field forwardVector:TVector = TVector.Create(0,0,1)
Field rightVector:TVector = TVector.Create(1,0,0)
Field upVector:TVector = TVector.Create(0,1,0)
Field pos:TVector = New TVector
Field headingQuaternion:TQuaternion = TQuaternion.Create()
Field pitchQuaternion:TQuaternion = TQuaternion.Create()
Field combinedRotation:TQuaternion = TQuaternion.Create()
Field gravityVector:TVector = TVector.Create(0,1,0)
'---------
'ChangeGravityVector
'---------
Method ChangeGravityVector(newGravityVector:TVector)
gravityVector = newGravityVector
End Method
'---------
'MoveForward
'---------
Method MoveForward(moveAmount:Float, noGravity:Byte = False)
Local vecRot:TVector
If(noGravity = True)
headingQuaternion.MultiplyByVector(forwardVector)
vecRot = combinedRotation.MultiplyByVector(forwardVector)
Else
vecRot = headingQuaternion.MultiplyByVector(forwardVector)
EndIf
vecRot.ScaleVector(moveAmount)
pos.AddVector(vecRot)
End Method
'---------
'MoveUp
'---------
Method MoveUp(moveAmount:Float, noGravity:Byte = False )
Local vecRot:TVector
If(noGravity = True)
headingQuaternion.MultiplyByVector(gravityVector)
vecRot = combinedRotation.MultiplyByVector(gravityVector)
Else
vecRot = headingQuaternion.MultiplyByVector(gravityVector)
EndIf
vecRot.ScaleVector(moveAmount)
pos.AddVector(vecRot)
End Method
'---------
'MoveRight
'---------
Method MoveRight(moveAmount:Float, noGravity:Byte = False )
Local vecRot:TVector
If(noGravity = True)
headingQuaternion.MultiplyByVector(rightVector)
vecRot = combinedRotation.MultiplyByVector(rightVector)
Else
vecRot = headingQuaternion.MultiplyByVector(rightVector)
EndIf
vecRot.ScaleVector(moveAmount)
pos.AddVector(vecRot)
End Method
'---------
'RotateX
'---------
Method RotateX(rotateAmount:Float)
Local xRotQuat:TQuaternion = TQuaternion.Create()
xRotQuat.ConvertFromAxisAngle(rightVector, rotateAmount)
pitchQuaternion = pitchQuaternion.MultiplyByQuaternion(xRotQuat)
End Method
'---------
'RotateY
'---------
Method RotateY(rotateAmount:Float)
Local yRotQuat:TQuaternion = TQuaternion.Create()
yRotQuat.ConvertFromAxisAngle(gravityVector, rotateAmount)
headingQuaternion = yRotQuat.MultiplyByQuaternion(headingQuaternion)
End Method
'---------
'GetCameraMatrix
'---------
Method GetCameraMatrix:TMatrix4x4()
combinedRotation = headingQuaternion.MultiplyByQuaternion(pitchQuaternion)
Return combinedRotation.GetMatrix()
End Method