50

3D プログラミングを学んでいると、次の 3 つの変換行列で考えるのが最も簡単だと教えられます。

  1. モデル マトリックス。このマトリックスはモデルごとに個別であり、必要に応じてオブジェクトを回転およびスケーリングし、最終的に 3D ワールド内の最終的な位置に移動します。「モデル マトリックスは、モデル座標をワールド座標に変換します」。

  2. ビューマトリックス. このマトリックスは通常、多数のオブジェクト (すべてではない場合) で同じであり、現在の「カメラ位置」に従ってすべてのオブジェクトを回転および移動します。3D シーンがカメラで撮影され、画面にレンダリングされるのはこのカメラでキャプチャされた画像であるとイメージする場合、カメラの位置とその視線方向によって、シーンのどの部分が見えるか、オブジェクトがどのように見えるかが決まります。キャプチャ画像に表示されます。単一フレームのレンダリング中にビュー マトリックスを変更する理由はほとんどありませんが、実際には存在します (たとえば、シーンを 2 回レンダリングし、その間にビュー マトリックスを変更することで、シーン内に非常にシンプルでありながら印象的なミラーを作成できます)。 . 通常、ビュー マトリックスは、描画される 2 つのフレーム間で 1 回だけ変更されます。"

  3. 射影行列。射影行列は、これらの 3D 座標が 2D 座標にどのようにマッピングされるかを決定します。たとえば、それらに遠近法が適用されるか (オブジェクトはビューアーから離れるほど小さくなります)、または適用されないか (直交投影) を決定します。射影行列はほとんど変化しません。ウィンドウにレンダリングしていてウィンドウ サイズが変更された場合、またはフル スクリーンでレンダリングしていて解像度が変更された場合は、変更が必要になることがありますが、新しいウィンドウ サイズ/画面解像度の表示アスペクト比が以前とは異なる場合に限ります。このマトリックスを変更したくなるクレイジーなエフェクトがいくつかありますが、ほとんどの場合、プログラムのライブ全体でほぼ一定です。「プロジェクション マトリックスは目の座標をスクリーン座標に変換します」.

これは私にとって非常に理にかなっています。もちろん、最初にベクトルを行列で乗算しA、次に行列で乗算することは、ベクトルを行列でB乗算することと同じであるため、常に 3 つの行列すべてを 1 つの行列に結合することができます。CC = B * A

従来の OpenGL (OpenGL 1.x/2.x) を見ると、OpenGL は射影行列を認識しています。しかし、OpenGL はモデルやビュー マトリックスを提供せず、モデルとビュー マトリックスを組み合わせたもののみを提供します。なんで?この設計では、適用されたモデル変換によって「破棄」されるため、「ビュー マトリックス」を永続的に保存して復元する必要があります。3 つの個別の行列がないのはなぜですか?

新しい OpenGL バージョン (OpenGL 3.x/4.x) を見て、従来のレンダリング パイプラインを使用せず、すべてをシェーダー (GLSL) でカスタマイズしている場合、使用可能なマトリックスがまったくないため、独自の行列を定義します。それでもほとんどの人は、射影行列とモデル ビュー行列の古い概念を保持しています。どうしてそうするか?モデル ビュー マトリックスを永続的に保存および復元する必要がないことを意味する 3 つのマトリックスを使用しない理由、または頂点シェーダーでのマトリックス乗算を節約する単一の結合されたモデル ビュー プロジェクション (MVP) マトリックスを使用しない理由レンダリングされた単一の頂点に対して(結局のところ、そのような乗算も無料ではありません)。

私の質問を要約すると、3 つの個別のマトリックスまたは単一の MVP マトリックスよりも、モデル ビュー マトリックスと個別の射影マトリックスを組み合わせた利点はどれですか?

4

3 に答える 3

40

実際に見てください。まず、送信するマトリックスが少ないほど、位置/法線/その他で乗算する必要があるマトリックスが少なくなります。したがって、頂点シェーダーが高速になります。

したがって、ポイント 1: マトリックスが少ないほど良いです。

ただし、おそらく実行する必要がある特定のことがあります。2D レンダリングやいくつかの単純な 3D デモ アプリケーションを実行している場合を除き、ライティングを行う必要があります。これは通常、位置と法線をワールドまたはカメラ (ビュー) 空間に変換してから、それらに対していくつかのライティング操作を行う必要があることを意味します (頂点シェーダーまたはフラグメント シェーダーのいずれかで)。

モデル空間から投影空間に移動するだけでは、それはできません。投影後の空間は非線形であるため、照明を行うことはできません。数学ははるかに複雑になります。

したがって、ポイント 2:モデルと投影の間に少なくとも1 つのストップが必要です。

したがって、少なくとも 2 つの行列が必要です。なぜモデルからワールドではなく、モデルからカメラなのですか? シェーダーでワールド空間で作業するのは悪い考えだからです。原点から離れた位置にある平行移動に関連する数値精度の問題が発生する可能性があります。一方、カメラ空間で作業した場合、カメラから遠すぎるものは何もないため、これらの問題は発生しません (もしそうであれば、おそらく遠深度面の外側にあるはずです)。

したがって、カメラ空間を照明の中間空間として使用します。

于 2012-05-16T11:52:51.270 に答える
2

ほとんどの場合、シェーダーにはシェーディング用のワールド座標またはアイ座標のジオメトリが必要になるため、投影マトリックスをモデルおよびビューマトリックスから分離する必要があります。

シェーダーにジオメトリを2つのマトリックスで乗算させると、パフォーマンスが低下します。各モデルにthousends(またはそれ以上)の頂点があると仮定すると、CPUでモデルビュー行列を1回計算し、シェーダーにmtrix-vectorの乗算を1つ少なくする方が効率的です。

于 2012-05-16T11:47:18.150 に答える
0

射影行列を分離することにより、z バッファーの戦いの問題を解決しました。GPU 負荷の目に見える増加はありません。次の 2 つのスクリーンショットは、2 つの結果を示しています。緑と白のレイヤーが争っていることに注意してください。

結合行列 別の投影

于 2021-09-16T12:20:53.427 に答える