モデルをターゲットに向ける


28

2つのオブジェクト(ターゲットとプレーヤー)があり、両方に位置(Vector3)と回転(四元数)があります。ターゲットを回転させて、プレイヤーの真正面に向けたいです。ターゲットは、何かを撃ったとき、プレイヤーを正しく撃ちます。

私はプレイヤーに強打の多くの例を見てきましたが、増分回転は望ましくありません、私は強打を100%にすることができ、実際に機能する限り、それは大丈夫だと思います。

参考までに、位置と回転を使用して他の多くのことを行うことはできません。この最後の作品を除いて、すべてうまくいきません。

コードサンプルは、Targetのクラスで実行されます。Position=ターゲットの位置、Avatar =プレーヤー。

編集

私は今、彼が提供したMaikのc#コードを使用しており、うまく機能しています!


4
100%slerpを実行している場合、slerpは使用していません。単に回転を設定しているだけです0*(rotation A) + 1*(rotation B)-つまり、回転を回転Bに設定しているだけです。Slerpは、回転がどのように見えるか(0%<x <100%)を決定するためのものです。
-doppelgreener

わかりましたが、ターゲットはまだプレーヤーに対して完全に回転していません...そのコードでは「長い道のり」です。
マーク

回答:


20

それを行うには複数の方法があります。絶対方向またはアバターに対する相対的な回転を計算できます。つまり、新しい方向= avatarOrientation * qです。後者は次のとおりです。

  1. アバターのユニット前方ベクトルとアバターからターゲットへのユニットベクトルの外積、新しい前方ベクトルを取得して、回転軸を計算します。

    vector newForwardUnit = vector::normalize(target - avatarPosition);
    vector rotAxis = vector::cross(avatarForwardUnit, newForwardUnit);
  2. 内積を使用して回転角度を計算する

    float rotAngle = acos(vector::dot(avatarForwardUnit, newForwardUnit));
  3. rotAxisとrotAngleを使用してクォータニオンを作成し、アバターの現在の方向で乗算します

    quaternion q(rotAxis, rotAngle);
    quaternion newRot = avatarRot * q;

アバターの現在の順方向ベクトルを見つけるのに助けが必要な場合、1の入力は撃つだけです:)

編集:絶対方向の計算は実際には少し簡単です。1)および2)の入力として、アバターの前方ベクトルの代わりに単位行列の前方ベクトルを使用します。3)で乗算しないで、代わりに直接新しい方向として使用します。newRot = q


重要な注意事項:このソリューションには、クロスプロダクトの性質に起因する2つの異常があります。

  1. 順方向ベクトルが等しい場合。ここでの解決策は、単純にIDクォータニオンを返すことです

  2. ベクトルが反対方向を正確に指している場合。ここでの解決策は、回転軸と角度180.0度としてアバターのアップ軸を使用してクォータニオンを作成することです。

これらのエッジケースを処理するC ++の実装を次に示します。C#に変換するのは簡単です。

// returns a quaternion that rotates vector a to vector b
quaternion get_rotation(const vector &a, const vector &b, const vector &up)
{   
    ASSERT_VECTOR_NORMALIZED(a);
    ASSERT_VECTOR_NORMALIZED(b);

    float dot = vector::dot(a, b);    
    // test for dot -1
    if(nearly_equal_eps_f(dot, -1.0f, 0.000001f))
    {
        // vector a and b point exactly in the opposite direction, 
        // so it is a 180 degrees turn around the up-axis
        return quaternion(up, gdeg2rad(180.0f));
    }
    // test for dot 1
    else if(nearly_equal_eps_f(dot, 1.0f, 0.000001f))
    {
        // vector a and b point exactly in the same direction
        // so we return the identity quaternion
        return quaternion(0.0f, 0.0f, 0.0f, 1.0f);
    }

    float rotAngle = acos(dot);
    vector rotAxis = vector::cross(a, b);
    rotAxis = vector::normalize(rotAxis);
    return quaternion(rotAxis, rotAngle);
}

編集:マークのXNAコードの修正バージョン

// the new forward vector, so the avatar faces the target
Vector3 newForward = Vector3.Normalize(Position - GameState.Avatar.Position);
// calc the rotation so the avatar faces the target
Rotation = Helpers.GetRotation(Vector3.Forward, newForward, Vector3.Up);
Cannon.Shoot(Position, Rotation, this);


public static Quaternion GetRotation(Vector3 source, Vector3 dest, Vector3 up)
{
    float dot = Vector3.Dot(source, dest);

    if (Math.Abs(dot - (-1.0f)) < 0.000001f)
    {
        // vector a and b point exactly in the opposite direction, 
        // so it is a 180 degrees turn around the up-axis
        return new Quaternion(up, MathHelper.ToRadians(180.0f));
    }
    if (Math.Abs(dot - (1.0f)) < 0.000001f)
    {
        // vector a and b point exactly in the same direction
        // so we return the identity quaternion
        return Quaternion.Identity;
    }

    float rotAngle = (float)Math.Acos(dot);
    Vector3 rotAxis = Vector3.Cross(source, dest);
    rotAxis = Vector3.Normalize(rotAxis);
    return Quaternion.CreateFromAxisAngle(rotAxis, rotAngle);
}

わかりました、質問の私の編集でわかるように、ショットを提供しました、コードが提供されています。何が問題なのかよくわかりません。aおよびbの入力は順方向ベクトルであるか、少なくともそうであると仮定します。
マーク

@Marcは、私の答えであなたのXNAコードの修正されたバージョンを見ます。rotAxisはGetRotationでクロス積後に正規化されなければならない)TargetPosition 2 - 、新しい前方ベクトルの1)の計算が間違っていた正規化AvatarPositionである必要があります。そこ2つの問題はなかった
はMaik Semder

@ Marc、2つの小さな変更:3)sourceとdestは既に正規化されています。GetRotationで再度正規化する必要はありません。4)GetRotationで絶対1 / -1をテストせず、ある程度の許容値を使用します。0.000001fを使用しました
Maik Semder

うーん、それはまだ機能していません。モデルでも同じスケーリングが発生し、ターゲットはアバターの方向に回転しません(コメントの中で、アバターをターゲットの方向に回転させようとしていることに気づきました...逆のはずです)...暴徒をプレイヤーに向かわせる(3人称カメラのアバター)。GetRotationメソッドは、ターゲットとアバターの現在の回転について何かを知っているべきではありません。たとえば、newForwardが適切に作成されていると思いますか?
マーク

オブジェクトがスケーリングされている場合、クォータニオンに単位長がないこと、つまりrotAxisが正規化されていないことを意味します。rotAxisの正規化で最後のコード変更を追加しましたか?ただし、現在のコードを示してください。それが機能しない場合の例については、次の値も投稿してください:newForward rotAngle rotAxisおよびreturned quaternion。mobのコードは同じになります。アバターで動作させると、オブジェクトの見出しを簡単に変更できます。
マイクセンダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.