2012-01-03 15 views
2

クォータニオンカメラが与えられた場合、プレーヤーが異なるサーフェス法線(ウォール)を歩くことができるとき、その回転をどのように計算できますか?クォータニオンカメラを使用して回転を計算するにはどうすればよいですか?

私は、プレイヤーが3D空間で天井と壁を歩くことができるゲームに取り組んでいます。私はジンバルロックを避けるために四元数カメラシステムを使用することを選択しました。上(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 

答えて

2

[OK]をクリックして、うまくいくソリューションを見つけました。それは間違っていると思いました。変更する必要のあるベクトルは上のベクトルだけで、他の2つのベクトルは前と後の両方に同じである必要があります。次のコードは、現在の四元数を新しい上のベクトルに揃えます。トリックは、現在のアップベクトルと新しいアップベクトルとの間のドット積の2乗と、その2つの間のクロスベクトルを使用して新しいクォータニオンを作成するというものでした。あなたは、2つの間であなたの現在の見出しとslerpでそれを掛けます。後で新しいアップベクトルを設定することを忘れないでください。 slerpで必要な任意の値を使用してスムーズにすることができます.1.0は即座に遷移します。

 Local newQuat:TQuaternion = New TQuaternion 
     Local cross:TVector = upVector.GetCrossProduct(newGravityVector) 
     Local dot:Float = upVector.GetDotProduct(newGravityVector) 
     Local dotSquare:Float = Sqr((1.0 + dot) * 2.0) 
     Local scale:Float = 1.0/dotSquare 
     newQuat.x = cross.x*scale 
     newQuat.y = cross.y*scale 
     newQuat.z = cross.z*scale 
     newQuat.w = dotSquare*0.5 

     newQuat = newQuat.MultiplyByQuaternion(headingQuaternion) 

     headingQuaternion = headingQuaternion.Slerp(headingQuaternion, newQuat, 1.0) 

     gravityVector = newGravityVector 
     upVector = newGravityVector 
関連する問題