1

3Dモデルの回転を記述するクォータニオンがあるとします。

私がやりたいのは、オブジェクト(rotationQuaternion、サイドベクトル...)が与えられた場合、それをターゲットポイントに位置合わせしたいということです。

宇宙船の場合、コックピットがターゲットを指すようにします。

これが私が持っているいくつかのコードです...それは私が望むことをしていません、そして私は理由がわかりません...

        if (_target._ray.Position != _obj._ray.Position)
        {
            Vector3 vec = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);
            float angle = (float)Math.Acos(Vector3.Dot(vec, _obj._ray.Direction));
            Vector3 cross = Vector3.Cross(vec, _obj._ray.Direction);

            if (cross == Vector3.Zero)
                cross = _obj._side;

            _obj._rotationQuaternion *= Quaternion.CreateFromAxisAngle(cross,angle);
        }
        // Updates direction, up, side vectors and model Matrix
        _obj.UpdateMatrix();

しばらくすると、rotationQuaternionはX、Y、Z、Wでほぼゼロで満たされます。

何か助けはありますか?ありがとう ;-)

4

3 に答える 3

3

これは、ロックオンターゲットローテーションのクォータニオンを取得するために使用したショートカットです。

Matrix rot = Matrix.CreateLookAt(_arrow.Position, _cube.Position, Vector3.Down);
_arrow.Rotation = Quaternion.CreateFromRotationMatrix(rot);

この例では、矢印と立方体をレンダリングしています。立方体は円を描いて動き回っています。上記のコードでは、矢印は常に立方体を指しています。(立方体が真上または真下にある場合、いくつかのエッジケースがあると思いますが)。

ここに画像の説明を入力してください

このクォータニオン(宇宙船からターゲットまで)を取得したらQuaternion.Lerp()、現在の船の回転と整列した船の回転の間を補間するために使用できます。これにより、回転がスムーズに移行します(ターゲットにスナップするだけではありません)。


*=ところで、割り当て時に使用しているため、回転がゼロに減少する可能性があります。

于 2012-11-07T11:55:04.493 に答える
2

あなたのコードは少しファンキーです。

if (_target._ray.Position != _obj._ray.Position)
{

これは正しい場合と正しくない場合があります。明らかに、equalsコンパレータをオーバーライドしました。ここで正しいことは、2つの(単位長)光線間の内積が1に近いことを確認することです。光線の原点が同じである場合、おそらく「位置」が等しいということは、それらが同じ。

  Vector3 vec = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);

これは特に間違っているようです。マイナス演算子が奇妙な方法でオーバーライドされていない限り、この方法で減算しても意味がありません。

これが私がお勧めするものの擬似コードです:

normalize3(targetRay);
normalize3(objectRay);
angleDif = acos(dotProduct(targetRay,objectRay));
if (angleDif!=0) {
  orthoRay = crossProduct(objectRay,targetRay);
  normalize3(orthoRay);
  deltaQ = quaternionFromAxisAngle(orthoRay,angleDif);
  rotationQuaternion = deltaQ*rotationQuaternion;
  normalize4(rotationQuaternion);
}

ここで注意すべき2つのこと:

  1. クォータニオンは可換ではありません。あなたのクォータニオンは回転する列ベクトルであると仮定しました。だから私は左側にdeltaQを置きました。*=演算子が何をしているのかは明確ではありません。
  2. 乗算後、クォータニオンを定期的に正規化することが重要です。そうしないと、小さなエラーが蓄積され、ユニットの長さから離れてドリフトし、あらゆる種類の悲しみを引き起こします。
于 2012-11-07T16:36:55.133 に答える
0

ああ、神様!機能した!!!

            Vector3 targetRay = Vector3.Normalize(_target._ray.Position - _obj._ray.Position);
        Vector3 objectRay = Vector3.Normalize(_obj._ray.Direction);
        float angle = (float)Math.Acos(Vector3.Dot(targetRay, objectRay));

        if (angle!=0)
        {
            Vector3 ortho = Vector3.Normalize(Vector3.Cross(objectRay, targetRay));
            _obj._rotationQuaternion = Quaternion.CreateFromAxisAngle(ortho, angle) * _obj._rotationQuaternion;
            _obj._rotationQuaternion.Normalize();
        }
        _obj.UpdateMatrix();

JCooperありがとうございます!!!

そしてニコ私はレルプのアイデアが好きです;-)

于 2012-11-07T20:36:50.337 に答える