Given a quaternion camera, how can I calculate its rotation when the player can walk on different surface normals (walls).
I'm working on a game which allows the player to walk on ceilings and walls in 3D space. I've opted to use a quaternion camera system to avoid Gimbal Lock. Given a set of up(0,1,0), right(1,0,0), and forward(0,0,1) vectors, I construct a quaternion. The player rotates around the up vector for heading and around the right vector for pitch.
Without changing gravity vectors, the camera works fine and allows the player to move about the environment as if it were a standard FPS game.
For simplicity, let's say the player can press a key which grabs the normal from the nearest collision surface that differs from their current normal, and assigns that as the new gravity vector.
Unfortunately, I've run into a brainblock, and cannot figure out how to properly get the new up, right, and forward vectors from this new gravity vector and apply them to the current rotation quaternion, or even if that is the correct way to tackle the problem. If it helps, the movement and rotation code for my camera is below.
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