给定一个四元数相机,当玩家可以在不同的表面法线(墙)上行走时,该如何计算其旋转角度。如何在使用四元数相机时计算旋转角度?
我正在制作一款游戏,允许玩家在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