球の周りの任意の回転


12

ユーザーが球の表面を動き回れるようにするメカニズムをコーディングしています。球上の位置は現在、thetaおよびとして保存されますphi。ここでthetaは、現在の位置のz軸とxz投影の間の角度(つまりy軸を中心とした回転)でphi、y軸から位置までの角度です。私はそれを不十分に説明しましたが、本質的にはtheta = yawphi = pitch

Vector3 position = new Vector3(0,0,1);
position.X = (float)Math.Sin(phi) * (float)Math.Sin(theta);
position.Y = (float)Math.Sin(phi) * (float)Math.Cos(theta);
position.Z = (float)Math.Cos(phi);
position *= r;

これは正確だと思いますが、間違っているかもしれません。半径のあるワールド空間の原点で、球の表面の周りを任意の疑似2次元方向に移動できる必要がありますr。たとえば、ホールディングWは球体の周りをプレーヤーの向きに対して上方向に移動する必要があります。

球体上の位置/方向を表すためにクォータニオンを使用する必要があると思いますが、正しい方法を考えることはできません。球面形状は、私の強力なスーツではありません。

基本的に、次のブロックを埋める必要があります。

public void Move(Direction dir)
{   
    switch (dir)
    {
        case Direction.Left:
            // update quaternion to rotate left
            break;
        case Direction.Right:   
            // update quaternion to rotate right
            break;
        case Direction.Up:
            // update quaternion to rotate upward
            break;
        case Direction.Down:
            // update quaternion to rotate downward
            break;
    }
}

プレイヤーがポールに到達したらどうなりますか?「上向き」と書いていることに気付きました。文字通り「上向き」(つまり、球体の表面から離れる)、「まっすぐ進む」、「北極に向かう」という意味ですか?画面の向きを変更できず、画面の「前」または「上」は常に北です)
マーティンソーカ

おそらく、言葉遣いが不十分だったのでしょう。プレイヤーは球体の表面から離れてはならず、枢軸を意識すべきではありません。したがって、「上」に移動すると、球体の表面に沿って、プレーヤーの向きに対して上方向に移動します。たとえば、(r、0,0)にあり、上に押すと、z +極に向かって移動しますが、移動し続ける場合は、ラップして移動し続ける必要があります。
azz

まだ1つの疑問が残っています。プレーヤーは方向を変更できますか(「左」と「右」を回転)?
マーティンソーカ

たぶん私が行くよ何のより良い例:で、プレイヤー(1,1,1)の左を保持するには、通過する、球の周りに回転させるだろう(~1.2,0,~-1.2)、その後、(-1,-1,-1)、その後、(~-1.2,0,~1.2)バックに(1,1,1)
azz

1
あなたは常にを追跡する場合thetaphi、あなたの位置のアップデートとして、あなたはあなたの問題は、不必要に複雑になっています。各フレーム(1つ(ヨー)が変化しない)およびVector3.Transorm球の周りの2つの回転軸を簡単に計算できます。これにより問題が簡単になりますが、phi&で切断されthetaます。
スティーブH

回答:


5

実際には、「両方の方法」を持つことはできないことがわかります:球体に「絶対的な方向」の感覚を持たないことを意図している場合(つまり、プレイヤーが常にポールに向かっているわけではない場合) )、プレーヤーの向きの概念が必要になります。これは、直観が示唆するかもしれないこととは反対に、球体の動きは平面上の動きとまったく同じではなく、局所的(まったく)でもないからです。球体の固有の曲率は、プレイヤーが自分自身を回転させるアクションを実行できることを意味します!

私が話していることの最も極端な例として、プレーヤーが赤道上の点から始まることを想像してください(便宜上、時計の文字盤が赤道に上からマップされ、プレーヤーを6時の位置に置きます)、「上向き」-北極に向かって。プレーヤーが北極までずっと歩いているとします。その後、彼らは12時の方向に直接向かいます。次に、北極から赤道に戻って、プレイヤーを直接右に移動させます。3時の位置で巻き上げられますが、右に動いても向きが変わらないため(アイデアは、彼らがどのように動いても顔は変わらないということです)、彼らはまだ12時のポイントに直面しています-彼らは今、赤道に沿って直面しています!さて、彼らを「後方」に動かして出発点(6時)に戻しましょう。その後、彼らはまだ赤道に面しているので、3時の方向に向いています-「個人的な」方向を変えずに球に沿って移動するだけで、北極に向かってから回転します赤道に沿って直面している!ある意味では、これは古い「ハンターが南に1マイル、西に1マイル、次に北に1マイル」という冗談の詳細です-しかし、ここでは球体の曲率を利用して方向を変更しています。同じ効果は、はるかに小さいスケールでも発生することに注意してください。

幸いなことに、クォータニオンはこの状況を処理します(ご自身で述べたように)。クォータニオンは任意の回転を表すため、球上の任意の「ポイントと方向」を効果的に表します:原点で「三軸」から開始し、任意の回転を与え、次に回転軸のいずれかの方向に1ユニットを移動することを想像してくださいZ軸ポイント。少し考えてみると、これにより、ユニット球体上のいくつかの「方向」(つまり、3軸のX軸とY軸の配置)がある点に到達し、すべての点+方向に到達できることがわかります。この方法で単位球体(Z軸を、原点から球体上の点までの線に沿って指すように割り当て、その後、トライアックスをその線に沿って原点に戻す)。そのうえ、クォータニオンの乗算は回転の構成に対応するため、説明する各操作は、「現在の方向」に適切に選択されたクォータニオンを乗算することで表すことができます。具体的には、(ユニット)クォータニオン(qx、qy、qz、qw)は、(arccos(qw)によって(qx、qy、qz)軸を中心に回転する)、その後(座標系の選択に応じて、c_aをcos(alpha)、s_aをsin(alpha)にする)を意味します3つのクォータニオンM_x =(s_a、0、0、c_a)、M_y =(0、s_a、0、c_a)、およびM_z =(0、0、s_a、c_a)は、方向Iの「回転(つまり移動)」を表します「現在、アルファが向いている」および「現在アルファが向いている方向と直交する方向に回転する」。(これらのクォータニオンの3番目は、「自分のキャラクターを自分の軸について回転させます」Cur_q = M_x * Cur_qプレイヤーが上に押したCur_q = M_y * Cur_q場合、またはプレイヤーが右に押した場合(または、おそらくCur_q = M_yinv * Cur_qプレイヤーが左を押した場合のように、M_yinvはM_y四元数の「逆」で、逆の回転を表します)。事前乗算または事後乗算のどちらを行うか、どちらの側に回転を適用するかに注意する必要があることに注意してください。率直に言って、試行錯誤して、両方の乗算を試し、どちらが機能するかを見て、それを解決するのが最も簡単かもしれません。

更新されたクォータニオンから球体上のポイント(およびキャラクターの向き)への移動も比較的簡単です。最後の段落の対応により、基底ベクトル(1、 「四元数によるベクトルの回転」操作v→qvq -1(ここでの乗算は四元数の乗算であり、ベクトルvを識別する)を介したフレームの0,0)、(0,1,0)および(0,0,1)=(x、y、z)と '退化四元数'(x、y、z、0))。たとえば、単位球上の位置は、zベクトルを変換するだけで取得できます:pos =(qx、qy、qz、qw)*(0、0、1、0)*(-qx、-qy、-qz、 qw)=(qx、qy、qz、qw)*(qy、-qx、qw、qz)=(2(qy * qw + qz * qx)、2(qz * qy-qw * qx)、(qz ^ 2 + qw ^ 2)-(qx ^ 2 + qy ^ 2)、0)、(2(qy*qw+qz*qx), 2(qz*qy-qw*qx), (qz^2+qw^2)-(qx^2+qy^2))単位球上の「変換された」ユーザーの座標になります(もちろん、任意の球の座標を取得するには、球の半径を掛けるだけです)。他の軸に対しても同様の計算が機能し、たとえばユーザーの向きを定義します。


正確に私が達成したいこと。オリエンテーションクォータニオンから位置を取得する正しい方法を考えることができませんでした。あなたが提供したものを使用して、私は書くことができますMove()手順が、正規化された軸(つまり、私の位置)を取得するには、私はちょうど取る(sin(qx),sin(qy),sin(qw)) * rでしょうか?
azz

@Derは正確ではありません-投稿を詳細で更新しますが、短いバージョンでは、クォータニオンを使用して、通常のv-> qvq <sup>で単位ベクトル、たとえば(0,0,1)を変換します-1 </ sup>操作。単純なベクトルを変換しているという事実は、(当然)ここにショートカットがあることを意味しますが、最終的な座標は四元数の値で線形ではなく2次です。
スティーブンスタドニッキー

1

このhttp://www.youtube.com/watch?v=L2YRZbRSD1kに似たものが欲しいと思う

48hのゲームジャム用に開発しました...コードはここからダウンロードできます... http://archive.globalgamejam.org/2011/evil-god

私はあなたのコードに似たものを使って3D座標を取得しました...しかし、私は惑星を回転させ、プレイヤーは同じ位置にいました、あなたは生き物の動きに興味があると思います、これは:

    // To add movement
    protected override void LocalUpdate(float seconds)
    {
        Creature.Alfa += Direction.X * seconds * Speed;
        Creature.Beta += Direction.Y * seconds * Speed;            
    }


    // To calculate position
       World.Planet.GetCartesian(Alfa, Beta, out Position); // as you do
       Matrix PositionMatrix = Matrix.CreateTranslation(Position) * World.Planet.RotationMatrix;           
       LastPositionAbsolute = PositionAbsolute;
       Vector3 Up = PositionAbsolute = Vector3.Transform(Vector3.Zero, PositionMatrix);           
       Up.Normalize();
       // This is to add and offset to the creature model position
       PositionAbsolute += Up * 8;  
      // calculate new forward vector if needed

       if ((PositionAbsolute - LastPositionAbsolute).Length() > 0.1f) {
           Forward = PositionAbsolute - LastPositionAbsolute;
           Forward.Normalize();
       }

       // Calculate the world transform with position, forward vector and up vector
       Matrix LocalWorld = Matrix.CreateWorld(PositionAbsolute, Forward, Up); 

       Transform = Matrix.CreateScale(Scale * ScaleFactor) * LocalWorld;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.