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