3Dカメラの回転


9

許してください、しかし私は助けを必要としています、そして私は今数週間これに行き詰まっています、私は進歩を遂げておらず、どこへ行っても私は別の答えを見ます、私が試みるすべてがうまくいきません。私は十分なヒントとアドバイスを持っています。今、私はこれを理解することができないので、誰かが私に後戻りするための答えをくれる人を本当に必要としています。

この主題を最も混乱させたのは、誰もが異なる規則または規則のセットを使用する方法であり、それらの答えは、何であるかを定義せずに独自の規則に基づいています。

だからここに私が最も一般的で論理的であると思われるものに基づいて形成した一連の規則があります:

  1. 軸の右手の法則。
  2. 正のYは上向き、正のZは視聴者向き、正のXは右向きです。
  3. シェーダーに送信されるときに転置される行メジャー行列。
    • ピッチ:X軸を中心とした回転
    • ヨー:Y軸を中心とした回転
    • ロール:z軸を中心とした回転
  4. ローテーション順:ロール、ピッチ、ヨー(これは正しいですか?誰かがこれを確認できますか?)
  5. 正の回転値は、軸の正の端から見下ろすと、時計回りに回転します。
  6. すべての軸にわたる0回転のデフォルトの方向は、負のYを指すベクトルです。

..それらの慣例を考えると(間違っている場合は必ず私を訂正してください!)

  • LookAt関数を記述しますか?(lookAt(ベクター位置、ベクターアイフォーカス、ベクターアップ))
  • 回転行列を計算します。(回転(x、y、z))

私はこれらの2つの質問に少なくとも過去3週間以上答えてみました。LookAt&Rotation Matrix関数を少なくとも30回書き直しました。何百ものウェブサイトと多くの解答された質問を読み、他の人々のコードをコピーしました、そして私がこれまでに作った何もうまくいきませんでした、すべてが間違った結果を生み出しました。それらのいくつかは、正しい回転にさえ近くないいくつかの陽気に奇妙な出力を生成しました。

私は昨夜を除いて毎晩これに取り組んできました。繰り返し失敗することにとてもイライラしていて、私は立ち止まって休憩しなければならなかったからです。

正しい方法を教えてください。それから逆に作業して、それがどのように機能するかを理解できます。正しい答えが得られず、これが私を少し狂わせています!

私はJavaで書いていますが、任意の言語で書かれたコードを使用します。私の3Dレンダリングコードのほとんどは実際には非常に見事に機能しています。それは理解できない数学にすぎません。

更新:解決済み

ご協力ありがとうございました!私は実際に私が実際に理解しているルックアット関数を手に入れました、そして私は幸せにすることができませんでした(誰かがぜひともそれを見たいと思っているなら)。

ピッチ/ヨー/ロール変数に基づいて回転行列を作成することを再試行しましたが、再び失敗したようですが、フリールックカメラのオイラー角を使用しようとしてダンプすることにしました。代わりに、クォータニオンクラスを作成し、そのパスを下る方が幸運かもしれません。それ以外の場合は、球座標としてピッチ/ヨーを使用し、回転には新しい機能のLookAt関数を使用します。

他の誰かが同様の問題に直面していて質問をしたい場合は、遠慮なくお問い合わせください。

助けてくれてありがとう!

回答:


15

あなたが探しているものは、この非常に良い説明にあります:http : //www.songho.ca/opengl/gl_transform.html

しかし、手で押さないとわかりにくいので、ここで説明します。

この時点で、5つの座標系とそれらの相互関係を考慮する必要があります。これらは、ウィンドウ座標、正規化されたデバイス座標、目座標、世界座標、オブジェクト座標です。

ウィンドウの座標は、画面上の「物理」ピクセルとして見ることができます。これらはウィンドウシステムが参照する座標であり、モニターのネイティブ解像度で操作する場合、これらは実際には個々のピクセルです。ウィンドウ座標系は2D整数であり、ウィンドウを基準にしています。ここで、x +は左、y +は原点を左上隅にして下にあります。これらは、たとえばを呼び出すときに発生しますglViewport

2番目のセットは、正規化されたデバイス座標です。これらは、アクティブなビューポートによって設定されたスペースを指します。ビューポートの可視領域は-1から+1になり、したがって、中心に原点があります。x +は左、y +は上です。また、z +がシーンから「外れ」になっています。これは、1で説明したとおりです。

正規化されたデバイス座標からウィンドウ座標に取得する方法は制御できません。これは暗黙的に行われます。あなたが持っている唯一のコントロールは、スルーglViewportまたは同様のものです。

openGLを使用する場合、最終結果は常に正規化されたデバイス座標になります。その結果、これらの中でシーンをレンダリングする方法を心配する必要があります。射影およびモデルビュー行列を単位行列に設定すると、これらの座標に直接描画できます。これは、たとえば全画面効果を適用するときに行われます。

次は目の座標です。これはカメラから見た世界です。その結果、原点はカメラにあり、デバイス座標のような同じ軸の調整が適用されます。

アイ座標からデバイス座標に取得するには、射影行列を作成します。最も単純なのは、値を適切にスケーリングする正投影です。透視投影はより複雑で、シミュレーションの透視図を含みます。

最後に、世界座標系があります。これは、世界が定義されている座標系であり、カメラはこの世界の一部です。ここで重要なのは、軸の方向は定義しとおりであることです。z +を上げたい場合は、それで十分です。

世界座標から目の座標に取得するには、ビューマトリックスを定義します。これはのようなもので行うことができますlookAt。この行列が行うことは、カメラが原点にあり、z軸を見下ろすように世界を「移動」することです。

ビュー行列を計算するのは驚くほど簡単ですが、カメラの変換を行う必要があります。基本的に、次のマトリックスを定式化する必要があります。

M=バツ[1]y[1]z[1]p[1]バツ[2]y[2]z[2]p[2]バツ[]y[]z[]p[]0001

x、y、zベクトルは、カメラから直接取得できます。見ての場合、ターゲット、eye(center)、upの値からそれらを導き出します。そのようです:

z=orメートルalzeeyetargetバツ=orメートルalzeあなたp×zy=zバツ

しかし、これらの値がたまたまある場合は、そのままにしてください。

pを取得するのは少し難しいです。これは、ワールド座標での位置ではなく、カメラ座標での位置です。ここでの簡単な回避策は、2つの行列を初期化することです。1つはx、y、zのみで、もう1つは-eyeで、それらを乗算します。結果はビューマトリックスです。

これがコードでどのように見えるかについて:

mat4 lookat(vec3 eye, vec3 target, vec3 up)
{
    vec3 zaxis = normalize(eye - target);    
    vec3 xaxis = normalize(cross(up, zaxis));
    vec3 yaxis = cross(zaxis, xaxis);     

    mat4 orientation(
       xaxis[0], yaxis[0], zaxis[0], 0,
       xaxis[1], yaxis[1], zaxis[1], 0,
       xaxis[2], yaxis[2], zaxis[2], 0,
         0,       0,       0,     1);

    mat4 translation(
              1,       0,       0, 0,
              0,       1,       0, 0, 
              0,       0,       1, 0,
        -eye[0], -eye[1], -eye[2], 1);

    return orientation * translation;
}

完全なコード

そして最後に、完全を期すために、オブジェクト座標系も用意しました。これは、メッシュが格納される座標系です。モデルマトリックスの助けを借りて、メッシュ座標は世界座標系に変換されます。実際には、モデルとビューマトリックスは、いわゆるモデルビューマトリックスに結合されます。


1
もし私がこの回答を100回賛成票を投じることができれば、私はそうします。私が混乱したすべてに対処し、コードとリンクも提供した徹底的で完全な回答に感謝します!私はこの問題について数学の本を読んだり、あなたの答えやサンプルコードとリンクされたページを読んだりして、これを理解するのに十分でないなら、ここでやめるべきです。最後のコードサンプルで1つの説明を求めることができれば、これらの行列は列のメジャー順であり、上記の行列は行のメジャー順であると言えるでしょうか。
Grady

これは少し混乱します。マトリックスは列優先ですが、列は行にあります。したがって、実際の数学をコードにマッピングするには、行列を転置する必要があります。github.com/rioki/glm/blob/master/src/matrix.h#l72を参照してくださいこれは、openGLに正確に対応し、を使用しfloat[16]た場合の状態を示しています。
rioki 14年

ああ、そう思ったのですが、確認したかったのですが、ありがとうございました!あなたは大きな助けになりました、私は本当に感謝しています。
Grady、2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.