クォータニオンカメラが与えられた場合、プレーヤーが異なるサーフェス法線(ウォール)を歩くことができるとき、その回転をどのように計算できますか?クォータニオンカメラを使用して回転を計算するにはどうすればよいですか?
私は、プレイヤーが3D空間で天井と壁を歩くことができるゲームに取り組んでいます。私はジンバルロックを避けるために四元数カメラシステムを使用することを選択しました。上(0,1,0)、右(1,0,0)、および順(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