Учитывая кватернионную камеру, как я могу рассчитать ее вращение, когда игрок может ходить по разным нормам поверхности (стенам).
Я работаю над игрой, которая позволяет игроку ходить по потолкам и стенам в трехмерном пространстве. Я решил использовать систему камер кватернионов, чтобы избежать Gimbal Lock. При заданном наборе векторов up (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