learnopengl。 レッスン1.8-座暙系

画像 前のレッスンでは、倉換行列で頂点を倉換するこずで埗られる利点に぀いお孊びたした。 OpenGLは、シェヌダヌの開始埌に衚瀺するすべおの頂点が、正芏化されたデバむス座暙NDCにあるず想定しおいたす。 これは、各頂点のx、y、z座暙が-1.0〜1.0の間でなければならないこずを意味したす。 この範囲倖の座暙は衚瀺されたせん。 通垞、自分で蚭定した範囲の座暙を指定し、頂点シェヌダヌでこれらの座暙をNDCに倉換したす。 次に、これらのNDCはラスタラむザヌに枡されお、画面の2次元座暙/ピクセルに倉換されたす。


座暙を正芏化しおからスクリヌン座暙に倉換するこずは、通垞、段階的に行われたす。最終的にスクリヌン座暙に倉換する前に、オブゞェクトの頂点をいく぀かの座暙系に倉換したす。 いく぀かの䞭間座暙系を介した座暙倉換の利点は、特定のシステムで䞀郚の操䜜/蚈算が簡単に実行できるこずです。これはすぐに明らかになりたす。 合蚈で、私たちにずっお重芁な5぀の異なる座暙系がありたす。


  1. ロヌカル空間たたはオブゞェクト空間
  2. ワヌルドスペヌス
  3. ビュヌのスペヌスたたはオブザヌバヌ
  4. クリッピングスペヌス
  5. スクリヌンスペヌス

ピヌクは、フラグメントになる前に、これらすべおの異なる状態に倉換されたす。


おそらく今、あなたは各空間たたは座暙系が䜕であるか完党に混乱しおいるので、党䜓像ず各空間が実際に䜕をするかを瀺すこずにより、それらをより理解しやすい圢で怜蚎したす。


䞀般的なスキヌム


座暙をある空間から別の空間に倉換するために、いく぀かの倉換行列を䜿甚したすが、その䞭で最も重芁なのはModel 、 ViewおよびProjection行列です。 頂点の座暙はロヌカル空間でロヌカル座暙ずしお始たり、その埌ワヌルド座暙に倉換され、次にビュヌの座暙 、 クリッピングに倉換され、最埌にすべおが画面座暙で終了したす 。 次の図は、このシヌケンスず各倉換の動䜜を瀺しおいたす。


画像

  1. ロヌカル座暙はオブゞェクトの座暙であり、オブゞェクト自䜓が始たる堎所にある参照ポむントを基準にしお枬定されたす
  2. 次のステップでは、ロヌカル座暙がワヌルド空間の座暙に倉換されたす。これは、意味では、より倧きな䞖界の座暙です。 これらの座暙は、ワヌルド基準点に関連しお枬定され、ワヌ​​ルド空間にある他のすべおのオブゞェクトに共通です
  3. さらに、各頂点がカメラたたは芳枬者の芖点から芋たように芋えるように、ワヌルド座暙をビュヌ空間の座暙に倉換したす
  4. 座暙がビュヌ空間に倉換されたら、クリッピング座暙に投圱したす。 クリッピング座暙は-1.0〜1.0の範囲で有効であり、画面に衚瀺される頂点を決定したす。
  5. 最埌に、ビュヌポヌトの倉換ず呌ばれる倉換プロセスで、
    クリッピング座暙を-1.0から1.0に倉換し、 glViewport関数で指定された画面座暙の領域に倉換したす。

このすべおの埌、受信した座暙はラスタラむザヌに送信され、それらがフラグメントに倉換されたす。


おそらく、各座暙空間の甚途を少し理解しおいるでしょう。 頂点をこれらの異なる座暙空間に倉換する理由は、特定の座暙系で䞀郚の操䜜がより理解可胜たたは単玔になるためです。

たずえば、ロヌカル空間でオブゞェクトを倉曎するのが最も合理的であり、他のオブゞェクトの䜍眮を考慮した操䜜の蚈算は、ワヌルド座暙などで行うのが最適です。 必芁に応じお、1぀の倉換行列を指定できたす。これにより、ロヌカル空間からクリッピング空間に1ステップで座暙が倉換されたすが、これにより柔軟性が倱われたす。


以䞋では、各座暙系に぀いお詳しく説明したす。


ロヌカルスペヌス


ロヌカル空間は、オブゞェクトに察しおロヌカルな座暙系です。 オブゞェクト自䜓ず同じポむントで開始したす。 モデリング゜フトりェアパッケヌゞでBlenderに䌌たキュヌブを䜜成したず想像しおください。 アプリケヌションの座暙内のキュヌブが別の堎所にある堎合でも、キュヌブの開始点はおそらく0,0,0にありたす。 䜜成したすべおのモデルに開始点0,0,0がある可胜性がありたす。 したがっお、モデルのすべおの頂点はロヌカル空間にありたす。すべおの座暙はオブゞェクトに察しおロヌカルです。


䜿甚したコンテナの頂点は、-0.5から0.5の間の座暙を䜿甚しお決定され、開始点は0.0です。 これらはロヌカル座暙です。


ワヌルドスペヌス


すべおのオブゞェクトをアプリケヌションに盎接むンポヌトする堎合、それらはおそらくワヌルド参照ポむント0,0,0の近くで互いの䞊に積み䞊げられたすが、これは望みどおりではありたせん。 より倧きなスペヌスに配眮するには、各オブゞェクトの䜍眮を決定する必芁がありたす。 ワヌルド空間の座暙、これはたさにその名前のずおりですゲヌムワヌルドに察するすべおの頂点の座暙。 これは、空間に分垃するようにそしおできれば珟実的にオブゞェクトが倉換されるのを芋たい座暙空間です。 オブゞェクトの座暙は、ロヌカル空間からワヌルド空間に倉換されたす。 これは、 モデルマトリックスを介しお行われたす。


モデルマトリックスは、オブゞェクトを移動、スケヌリング、および/たたは回転しお、オブゞェクトが存圚するべき䜍眮/方向でワヌルド空間に配眮するマトリックスです。 これは、拡倧されたロヌカルスペヌスでは倧きすぎた建物を郊倖に移動し、Y軞に沿っおわずかに巊に曲がっお隣接する家にぎったり合う建物の倉圢ずしお想像しおください。 コンテナをシヌン内で移動した前のレッスンのマトリックスを、䞀皮のモデルマトリックスずしお認識するこずができたす。 その助けを借りお、シヌン/䞖界のさたざたな堎所に配眮するために、コンテナのロヌカル座暙を再集蚈したした。


衚瀺スペヌス


ビュヌスペヌスは、通垞OpenGL カメラず呌ばれるものです カメラスペヌスたたはオブザヌバヌ スペヌスずも呌ばれたす 。 ビュヌ空間は、䞖界座暙をナヌザヌが正面から芋おいるように芋える座暙に倉換した結果です。 したがっお、ビュヌスペヌスは、カメラのビュヌファむンダヌを通しお芋えるスペヌスです。 これは通垞、䞀郚のオブゞェクトがカメラの前にあるようなシヌンのシフトず回転の組み合わせによっお実珟されたす。 これらの結合された倉換は、通垞、ワヌルド座暙をビュヌ空間に倉換するビュヌマトリックスに栌玍されたす。 次のレッスンでは、このようなビュヌマトリックスを䜜成しおカメラをシミュレヌトする方法に぀いお広範囲に説明したす。


クリッピングスペヌス


頂点シェヌダヌが終了するず、OpenGLはすべおの座暙が特定の範囲内にあり、その境界を超えるすべおのものが切断されるこずを予期したす。 カットオフ座暙は砎棄され、残りの座暙は画面䞊に衚瀺されるフラグメントになりたす。 それがクリッピングスペヌスの名前の由来です。


[-1.0、1.0]の範囲の倀ですべおの可芖座暙を蚭定するこずは実際には盎感的ではないため、䜜業のために独自の座暙セットを定矩し、OpenGLが期埅するようにNDCに倉換したす。


ビュヌ空間からクリッピング空間に座暙を倉換するために、たずえば各軞に沿っお-1000から1000たでの座暙の範囲を定矩する、いわゆる射圱行列を定矩したす。 射圱行列は、この範囲の座暙をデバむスの正芏化された座暙-1.0、1.0に倉換したす。 指定された間隔倖のすべおの座暙ぱリア[-1.0、1.0]に該圓しないため、切り取られたす。 射圱行列によっお蚭定された範囲では、座暙1250、500、750は衚瀺されたせん。Xコンポヌネントが境界を超えるため、NDCで1.0を超える倀に倉換され、したがっお頂点がクリップされるためです。 。

䞉角圢などのプリミティブ党䜓ではなく、その䞀郚のみがカットオフボリュヌムの倖偎にある堎合、OpenGLは完党にカットオフ範囲にある1぀以䞊の䞉角圢の圢でこの䞉角圢を再構築するこずに泚意しおください。

投圱行列によっお定矩されるこの衚瀺ボリュヌムは、錐台ピラミッドず呌ばれ、このピラミッドに入る各座暙はナヌザヌの画面に衚瀺されたす。 特定の範囲の座暙をデバむスの正芏化された座暙NDCに倉換するプロセス党䜓は、プロゞェクションマトリックスが3D座暙をデバむスの単玔な2Dに倉換された正芏化された座暙に投圱するため、プロゞェクションず呌ばれたす。


すべおの頂点の座暙がクリッピングスペヌスに転送されるずすぐに、 パヌスペクティブ分割ず呌ばれる最終操䜜が実行されたす。 その䞭で、頂点䜍眮ベクトルのx、y、z成分をベクトルwの同次成分で陀算したす。 パヌスペクティブ陀算は、クリッピングスペヌスの4D座暙をデバむスの3次元の正芏化された座暙に倉換したす。 このステップは、各頂点シェヌダヌの完了埌に自動的に実行されたす。


この段階の埌、受信した座暙 glViewport蚭定を䜿甚は画面座暙に衚瀺され、フラグメントに倉わりたす。


投圱行列は、ビュヌ座暙をクリッピング座暙に倉換し、2぀の異なる圢状をずるこずができたす。各圢状は、独自の特別な切頭ピラミッドを定矩したす。 正射投圱行列たたはパヌスペクティブを䜜成できたす。


正投圱


正投圱図法は、平行四蟺圢の圢で切り捚おられたピラミッドを定矩したす。平行四蟺圢は、ボリュヌムの倖偎のすべおの頂点がクリップされるクリッピングスペヌスです。 正射投圱行列を䜜成するずき、衚瀺されるクリッピングピラミッドの幅、高さ、および長さを指定したす。 投圱行列によっおクリッピングスペヌスに倉換された埌、ピラミッドで囲たれたボリュヌムに含たれるすべおの座暙はクリップされたせん。 切り捚おられたピラミッドは、コンテナのように芋えたす。



切り捚おおられた正投圱図ピラミッド

角錐台は、可芖座暙の領域を定矩し、幅、高さ、 近接および遠方の平面によっお定矩されたす。 ニアプレヌンの前にある座暙は、リアプレヌンの埌ろにある座暙ず同じように切り取られたす。 正投圱の角錐台は、それに含たれる座暙をデバむスの正芏化された座暙に盎接倉換し、ベクトルのwコンポヌネントは䜿甚されたせん。 wコンポヌネントが1.0の堎合、遠近法による分割は座暙倀を倉曎したせん。


正射投圱行列を䜜成するには、 glm :: orthoず呌ばれる組み蟌みGLMラむブラリ関数を䜿甚したす。


glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f ); 

最初の2぀のパラメヌタヌは、切り捚おられたピラミッドの巊右の座暙を決定し、3番目ず4番目のパラメヌタヌは、ピラミッドの䞋限ず䞊限を指定したす。 これらの4぀のポむントは、ニアプレヌンずファヌプレヌンの寞法を蚭定し、5番目ず6番目のパラメヌタヌはそれらの間の距離を瀺したす。 この特定の投圱行列は、x、y、およびzの倀の範囲に入るすべおの座暙をデバむスの正芏化された座暙に倉換したす。


正射投圱行列は、座暙である2次元平面ディスプレむに盎接衚瀺されたすが、実際には、 透芖図を考慮しおいないため、盎接投圱は非珟実的な結果をもたらしたす。 これにより、 透芖投圱行列が修正されたす。


透芖投圱


珟実䞖界を芋たこずがあれば、遠くにあるオブゞェクトがはるかに小さく芋えるこずにおそらく気づいたでしょう。 私たちはこの奇劙な効果の芖点を呌び出したす 。 次の図に瀺すように、無限の高速道路たたは鉄道の終点を芋るず、特に目立ちたす。


遠近法

ご芧のように、芖点から芋るず、線がより収束するほど、線はより遠くにあるように芋えたす。 これはたさに、透芖投圱がシミュレヌトしようずしおいる効果であり、透芖投圱のマトリックスを通じお達成されたす。 射圱行列は、切り捚おられたピラミッドの指定された範囲をクリッピングスペヌスにマッピングし、同時に、頂点が芳枬者から遠ざかるほどこのw倀が倧きくなるように各頂点のwコンポヌネントを操䜜したす。 座暙をクリッピングスペヌスに倉換した埌、それらはすべお-wからwの範囲に入りたすこの範囲倖の頂点はクリップされたす。 OpenGLでは、頂点シェヌダヌの最終出力が-1.0〜1.0の座暙であるこずが必芁です。 したがっお、座暙がクリッピング空間にある堎合、遠近法の分割がそれらに適甚されたす。


パヌスペクティブ郚門フォヌミュラ


頂点座暙の各コンポヌネントは、ビュヌアヌからの距離に比䟋しお座暙倀を枛らす独自のwコンポヌネントに分割されたす。 これは、透芖投圱に圹立぀ため、wコンポヌネントの重芁性のもう1぀の理由です。 この埌に取埗される座暙は、デバむスの正芏化された空間にありたす。 盎亀射圱行列がどのように蚈算されるかを理解するこずに興味がある堎合そしお数孊を恐れるこずはありたせん、Songho によるこの玠晎らしい蚘事をお勧めしたす。


GLMラむブラリの透芖投圱行列は、次のように䜜成できたす。


 glm::mat4 proj = glm::perspective( 45.0f, (float)width/(float)height, 0.1f, 100.0f); 

glm ::パヌスペクティブは、目に芋えるスペヌスを定矩する切り捚おられたピラミッドを䜜成し、その倖偎にあり、クリッピングスペヌスのボリュヌムに入らないものはすべお切り取られたす。 予想される切り捚おられたピラミッドは、台圢のボックスずしお衚すこずができ、各内郚座暙はクリッピングスペヌス内のポむントにマッピングされたす。 パヌスペクティブトランケヌトピラミッドの画像を以䞋に瀺したす。


遠近法ピラミッド

最初のパラメヌタヌは、「 芖野 」を意味するfov 芖野の倀を蚭定し、可芖領域の倧きさを決定したす。 珟実的な衚珟のために、このパラメヌタヌは通垞45.0fに蚭定されたすが、同様の運呜のスタむルを埗るために、倧きな倀を蚭定するこずもできたす。 2番目のパラメヌタヌは、ビュヌポヌトの幅を高さで割るこずによっお蚈算されるアスペクト比を蚭定したす。 3番目ず4番目のパラメヌタヌは、角錐台の近くの平面ず遠くの平面を定矩したす。 通垞、最も近い距離を0.1fに蚭定し、最も遠い距離を100.0fに蚭定したす。 ニアプレヌンずファヌプレヌンの間に䜍眮し、切り捚おられたピラミッドのボリュヌム内にあるすべおの頂点が芖芚化されたす。


投圱行列のニアプレヌンたでの距離が倧きすぎるず10.0fなど、OpenGLはカメラの隣にあるすべおの座暙0.0〜10.0fを切り取りたす。これにより、ビデオゲヌムでおなじみの芖芚効果が埗られたす。近づきすぎた堎合は、䞀郚のオブゞェクトを透かしお芋たす。

盎亀投圱を䜿甚する堎合、各頂点座暙は、仮想の遠近法による分割なしでクリッピング空間に盎接マップされたす遠近法による分割は実行されたすが、wコンポヌネントは結果に圱響を䞎えないため1のたた、効果はありたせん。 正射投圱では遠近法が考慮されないため、さらに配眮されたオブゞェクトは小さく芋えず、奇劙な芖芚的印象を䞎えたす。 このため、正射投圱法は、䞻に2Dレンダリングや、建築や工孊のさたざたな甚途に䜿甚されたすが、遠近法による歪みがないこずが望たれたす。 Blender for 3Dモデリングなどのアプリケヌションでは、各オブゞェクトの枬定倀ず比率をより正確に衚瀺するため、モデリング䞭に正投圱が䜿甚されるこずがありたす。 以䞋は、Blenderの䞡方の投圱方法の比范です。


投圱比范


透芖投圱では、削陀された頂点がはるかに遠くなるこずがわかりたすが、正投圱では、頂点の削陀速床は同じであり、芳枬者たでの距離に䟝存したせん。


すべおをたずめる


䞊蚘の各ステップモデル、ビュヌ、投圱マトリックスの倉換マトリックスを䜜成したす。 頂点座暙は、次のようにクリッピングスペヌスの座暙に倉換されたす。


クリッピング座暙座暙匏


行列の乗算の順序が逆になっおいるこずに泚意しおください行列の乗算は右から巊に読み取らなければならないこずに泚意しおください。 結果の頂点座暙は、組み蟌み倉数gl_Positionを䜿甚しお頂点シェヌダヌで割り圓おる必芁がありたす。その埌、OpenGLは自動的に遠近法の分割ずクリッピングを実行したす。


それで䜕
頂点シェヌダヌ出力の座暙はクリッピング空間内にある必芁がありたす。これは、倉換マトリックスの助けを借りお達成したものです。 OpenGLは、クリッピングスペヌスの座暙の透芖分割を実行しお、それらを正芏化されたデバむス座暙に倉換したす
次に、OpenGLはglViewPortのパラメヌタヌを䜿甚しお、デバむスの正芏化された座暙を、各座暙が画面䞊のポむントに察応する画面座暙にマッピングしたすこの堎合、これは800x600の領域です。 このプロセスはビュヌポヌト倉換ず呌ばれたす。

このトピックを理解するのは難しいので、各スペヌスが䜕に䜿甚されおいるのかただよくわからない堎合は心配する必芁はありたせん。

以䞋に、これらの座暙空間を効果的に䜿甚する方法を瀺したす。今埌のレッスンでは十分な䟋がありたす。


3Dに移動


3D座暙を2D座暙に倉換する方法がわかったので、これたでに瀺した欠陥のある2D平面ではなく、オブゞェクトを実際の3Dオブゞェクトずしお衚瀺し始めるこずができたす。


3Dでの描画を開始するには、最初にモデルマトリックスを䜜成したす。 モデルマトリックスは、オブゞェクトのすべおの頂点をグロヌバルワヌルド空間に倉換するために適甚するシフト、スケヌリング、および/たたは回転で構成されたす。 X軞に沿っお回転させお、平面が床に暪たわっおいるように芋えるようにしお、平面を少し倉曎したしょう。 モデルのマトリックスは次のようになりたす。


 glm::mat4 model; model = glm::rotate(model, -55.0f, glm::vec3(1.0f, 0.0f, 0.0f); 

頂点の座暙にこのモデルのマトリックスを掛けお、それらをワヌルド座暙に倉換したす。 床に暪たわっおいる飛行機は、このように䞖界空間の飛行機を衚しおいたす。


次に、ビュヌマトリックスを䜜成する必芁がありたす。 オブゞェクトが衚瀺されるようにするには、シヌン内を少し戻す必芁がありたすワヌルド空間での芳枬者の芖点は原点0,0,0にあるため。 シヌン内を移動するには、次のこずを考慮しおください。


カメラを埌方に移動するこずは、シヌン党䜓を前方に移動するこずず同じです。

これがたさにビュヌマトリックスの機胜です。シヌン党䜓を、カメラを移動したい方向ず反察の方向に移動したす。 埌方に移動する必芁があり、OpenGLが正しい座暙系を䜿甚するため、z軞の正の方向に移動する必芁がありたす。 これを行うには、シヌン党䜓をz軞の負の偎にシフトしたす。 これは、私たちが埌退しおいるような印象を䞎えたす。


正しい座暙系

慣䟋により、OpenGLは正しい座暙系です。 , X , Y , Z (. ). , , Z . :


正しい座暙系の軞


, , :

  • Y .
  • .
  • .
  • 90 .

, X, — Y, z. , , Z . DirectX. , OpenGL ( ).


. :


 glm::mat4 view; //  ,        ,      view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); 

, — . , :


 glm::mat4 projection; projection = glm::perspective(45.0f, screenWidth / screenHeight, 0.1f, 100.0f); 

GLM. fov 45 , GLM fov , glm::radians(45.0).

, , . uniform :


 #version 330 core layout (location = 0) in vec3 position; ... uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { // ,       gl_Position = projection * view * model * vec4(position, 1.0f); ... } 

( , ):


 GLint modelLoc = glGetUniformLocation(ourShader.Program, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); ... //        

, , , :



, :


オブゞェクトの透芖図


3D-, - . , , .


3D


2D-, 3D-, 2D- 3D-.

36 (6 * 2 * 3 ). 36 , . , , .


«» , glVertexAttribPointer:


 // Position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); ... // TexCoord attribute glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); 

:


 model = glm::rotate(model, (GLfloat)glfwGetTime() * 50.0f, glm::vec3(0.5f, 1.0f, 0.0f)); 

glDrawArrays, 36 .


 glDrawArrays(GL_TRIANGLES, 0, 36); 

- :




, - . . , , OpenGL --, , , . - , .


, OpenGL Z- , OpenGL , , . Z-, OpenGL .


Z-


OpenGL Z-, . GLFW ( , ). ( z-) , , OpenGL Z-, , . OpenGL .


, , OpenGL , , - . glEnable . glEnable glDisable / OpenGL. OpenGL /, /. , GL_DEPTH_TEST :


 glEnable(GL_DEPTH_TEST); 

, ( ). , glClear GL_DEPTH_BUFFER_BIT :


 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

, OpenGL :



以䞊です , , . .


!


, 10 . , . , , . , — , .


-, , . 10 glm::vec3:


 glm::vec3 cubePositions[] = { glm::vec3( 0.0f, 0.0f, 0.0f), glm::vec3( 2.0f, 5.0f, -15.0f), glm::vec3(-1.5f, -2.2f, -2.5f), glm::vec3(-3.8f, -2.0f, -12.3f), glm::vec3( 2.4f, -0.4f, -3.5f), glm::vec3(-1.7f, 3.0f, -7.5f), glm::vec3( 1.3f, -2.0f, -2.5f), glm::vec3( 1.5f, 2.0f, -2.5f), glm::vec3( 1.5f, 0.2f, -1.5f), glm::vec3(-1.3f, 1.0f, -1.5f) }; 

, glDrawArrays 10 , . , 10 . , .


 glBindVertexArray(VAO); for(GLuint i = 0; i < 10; i++) { glm::mat4 model; model = glm::translate(model, cubePositions[i]); GLfloat angle = 20.0f * i; model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f)); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); glDrawArrays(GL_TRIANGLES, 0, 36); } glBindVertexArray(0); 

, 10 . , :


倚くのテクスチャキュヌブ


いいね , . , , .


挔習


Source: https://habr.com/ru/post/J324968/


All Articles