OpenGL には、原点 (0,0,0) を持つワールド座標系が 1 つあります。
私を混乱させるのは、glTranslate、glRotate などのすべての変換が行うことです。ワールド座標でオブジェクトを移動しますか、それともカメラを移動しますか? ご存知のように、オブジェクトを動かすかカメラを動かすことで同じ動きを実現できます。
glTranslate、glRotate、オブジェクトの変更、および gluLookAt がカメラを変更すると推測していますか?
OpenGL には、原点 (0,0,0) を持つワールド座標系が 1 つあります。
私を混乱させるのは、glTranslate、glRotate などのすべての変換が行うことです。ワールド座標でオブジェクトを移動しますか、それともカメラを移動しますか? ご存知のように、オブジェクトを動かすかカメラを動かすことで同じ動きを実現できます。
glTranslate、glRotate、オブジェクトの変更、および gluLookAt がカメラを変更すると推測していますか?
OpenGL には、原点 (0,0,0) を持つワールド座標系が 1 つあります。
まあ、技術的にはいいえ。
私を混乱させるのは、glTranslate、glRotate などのすべての変換が行うことです。ワールド座標でオブジェクトを移動しますか、それともカメラを移動しますか?
ない。OpenGL はオブジェクトを認識せず、OpenGL はカメラを認識せず、OpenGL はワールドを認識しません。OpenGL が気にかけているのは、プリミティブ、ポイント、ラインまたはトライアングル、頂点ごとの属性、正規化されたデバイス座標 (NDC)、および NDC がマップされるビューポートだけです。
OpenGL にプリミティブを描画するように指示すると、各頂点はその属性に従って処理されます。位置は属性の 1 つであり、通常はローカル「オブジェクト」座標系内の 1 ~ 4 個のスカラー要素を持つベクトルです。当面のタスクは、何らかの方法でローカル頂点位置属性をビューポート上の位置に変換することです。最新の OpenGL では、頂点シェーダーと呼ばれる GPU 上で実行される小さなプログラム内でこれが発生します。頂点シェーダーは、任意の方法で位置を処理できます。しかし、通常のアプローチは、いくつかの非特異な線形変換を適用することです。
このような変換は、同種の変換行列で表すことができます。3 次元ベクトルの場合、4 番目の要素が 1 である 4 つの要素を持つベクトルの同次表現。
コンピュータ グラフィックスでは、3 重変換パイプラインが一種の標準的な方法になっています。最初に、オブジェクトのローカル座標が、仮想の「目」に対する座標に変換されます。したがって、目空間に変換されます。OpenGL では、この変換はモデルビュー変換と呼ばれていました。目の空間の頂点位置を使用すると、イルミネーションのようないくつかの計算が一般化された方法で表現できるため、これらの計算は目の空間で行われます。次に、目空間座標がいわゆるクリップ空間に変換されます。この変換はいくつかをマッピングしますジオメトリがクリッピングされる、特定の境界を持つ特定のボリュームへの目の空間のボリューム。この変換は効果的に射影を適用するため、OpenGL では射影変換と呼ばれていました。
クリップ空間の後、位置は同種のコンポーネントによって「正規化」され、正規化されたデバイス座標が生成され、ビューポートに単純にマップされます。
要約すると:
頂点位置は、ローカル空間からクリップ空間に変換されます。
vpos_eye = MV · vpos_local
eyespace_calculations(vpos_eye);
vpos_clip = P · vpos_eye
·: inner product column on row vector
そしてNDCに到着
vpos_ndc = vpos_clip / vpos_clip.w
最後にビューポートへ (NDC 座標は [-1, 1] の範囲にあります)
vpos_viewport = (vpos_ndc + (1,1,1,1)) * (viewport.width, viewport.height) / 2 + (viewport.x, viewport.y)
*: vector component wise multiplication
OpenGL 関数 glRotate、glTranslate、glScale、glMatrixMode は、変換行列を操作するだけです。OpenGL には、4 つの変換行列がありました。
マトリックス操作関数が作用するものは、glMatrixMode を使用して設定できます。行列操作関数のそれぞれは、それらが記述した変換行列を選択行列の上に乗算することによって新しい行列を構成し、それによってそれを置き換えます。関数 glLoadIdentity は現在の行列を単位に置き換え、glLoadMatrix はそれをユーザー定義の行列に置き換え、glMultMatrix はその上にユーザー定義の行列を乗算します。
では、モデルビュー マトリックスはオブジェクトの配置とカメラの両方をどのようにエミュレートするのでしょうか。まあ、あなたがすでに述べたように
ご存知のように、オブジェクトを動かすかカメラを動かすことで同じ動きを実現できます。
それらを実際に区別することはできません。通常のアプローチは、オブジェクト ローカルから目への変換を 2 つのステップに分割することです。
これらは共に、モデルビューマトリックスによって記述される固定関数 OpenGL で、モデル ビューを形成します。変換の順序は
vpos_world = M · vpos_local
vpos_eye = V · vpos_world
で代用できます
vpos_eye = V · ( M · vpos_local ) = V · M · vpos_local
モデルビューマトリックスV · M
で置き換える_=: MV
vpos_eye = MV · vpos_local
したがって、複合行列 M の V と M は、modelview 行列に乗算する操作の順序によってのみ決定され、どのステップで「ここからモデル変換と呼ぶか」を決定することがわかります。
つまり、直後に
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
ビューが定義されます。しかし、ある時点でモデル変換を適用し始め、その後はすべてモデルになります。
最新の OpenGL では、すべての行列操作関数が削除されていることに注意してください。OpenGL のマトリックス スタックは完全な機能ではなく、本格的なアプリケーションで実際に使用されることはありませんでした。ほとんどのプログラムglLoadMatrix
は、自己計算された行列を編集するだけで、OpenGL 組み込みの行列操作ルーチンを気にしませんでした。
そして、シェーダーが導入されて以来、OpenGL マトリックス スタック全体が使いにくくなりました。
評決: OpenGL を最新の方法で使用する予定がある場合は、組み込み関数を気にしないでください。ただし、シェーダーが行うことは、OpenGL の固定関数パイプラインが行うことと非常に似ているため、私が書いたことを覚えておいてください。
OpenGL は低レベルの API であり、「シーン」には「オブジェクト」や「カメラ」のような高レベルの概念がないため、マトリックス モードは 2 つしかありません: MODELVIEW (「カメラ」マトリックスと「オブジェクト」変換) および投影 (ワールド空間から遠近法後の空間への射影変換)。
「モデル」マトリックスと「ビュー」マトリックス (オブジェクトとカメラ) の区別は、ユーザー次第です。glRotate/glTranslate 関数は、現在選択されている行列を指定された行列で乗算するだけです (ModelView と Projection を区別することさえありません)。
これらの関数は、現在の行列セットを乗算 (変換) するglMatrixMode()
ため、作業中の行列に依存します。OpenGL には 4 種類の行列があります。GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE、および GL_COLOR のいずれかの関数は、これらのマトリックスのいずれかを変更できます。したがって、基本的に、オブジェクトを変換するのではなく、さまざまなマトリックスを操作してその効果を「偽造」します。
glulookat()
は、平行移動とそれに続くいくつかの回転に相当する単なる便利な機能であり、特別なことは何もないことに注意してください。
すべての変換は、オブジェクトの変換です。gluLookAtでさえ、カメラが指示された場所にあるかのようにオブジェクトを変換するための単なる変換です。技術的には、それらは頂点の変換ですが、それは単なるセマンティクスです。
そうです、glTranslate、glRotate はレンダリング前にオブジェクト座標を変更し、gluLookAt はカメラ座標を変更します。