给定一个四元数相机,当玩家可以在不同的表面法线(墙壁)上行走时,我如何计算它的旋转。
我正在开发一款允许玩家在 3D 空间中在天花板和墙壁上行走的游戏。我选择使用四元数相机系统来避免万向节锁定。给定一组 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