なぜチュートリアルがOpenGLレンダリングに異なるアプローチを使用するのですか?


43

http://www.sdltutorials.com/sdl-opengl-tutorial-basics

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/

これら2つのチュートリアルは、まったく同じ結果を得るためにまったく異なるアプローチを使用しています。最初はのようなものを使用しglBegin(GL_QUADS)ます。2つ目はvertexBufferObjects、GLEWに基づいたシェーダーなどを使用します。しかし、結果は同じです。基本的な形状が得られます。

なぜこれらの違いが存在するのですか?

最初のアプローチは理解しやすいようです。複雑な2番目のアプローチの利点は何ですか?


4
猫の皮をむく唯一の方法はありません。
フィリップ

4
@Philippはい、しかし正しい方法と間違った方法、古い方法と新しい方法があります(そして以下の答えが示すように、古い方法と新しい方法はすべての状況で互換性がないかもしれません)
アンドリューヒル

3
正しい方法と間違った方法はなく、悪い方法と良い方法しかありません(いくつかの異なる次元で)。
user253751

glBeginglEnd現在のグラフィックスアーキテクチャに対しては非常に非効率的であるため非推奨となっています。
アレックス

回答:


77

OpenGLには4つの異なるメジャーバージョンがあり、モバイルデバイスと組み込みシステム(OpenGL | ES)およびJavaScript経由のWeb(WebGL)のバージョンはカウントしません。Direct3D 11がDirect3D 8とは異なる方法で行うように、OpenGL 3もOpenGL 1とは異なる方法で処理します。大きな違いは、OpenGLバージョンはほとんどの場合、古いバージョンへのアドオンにすぎません(ただし、完全に)。

OpenGLのさまざまなエディションとバージョンに加えて、メインのOpenGLはプロファイルの概念も追加しました。つまり、互換性プロファイル(古いバージョンのAPIのサポートを有効にする)とコアプロファイル(これらの古いAPIを無効にする)です。以下のようなものはglBegin、あなたがコアプロファイルを使用する場合がありますが(デフォルトで)互換性プロファイルを使用する際に、単純に仕事をしません。

さらに大きな問題として、OpenGLの一部の実装(特にAppleのようなもの)では、コアプロファイルを使用している場合にのみ新しいOpenGL機能が有効になります。つまり、新しいAPIを使用するには、古いAPIの使用を停止する必要あります。

その後、チュートリアルのいくつかの非常にわかりにくいシナリオになります。

  1. チュートリアルは古く、廃止されたAPIのみを使用します。
  2. このチュートリアルは新しく、よく書かれており、コア互換のAPIのみを使用しています。
  3. このチュートリアルは新しいものですが、互換モードですべてのAPIを有効にし、新しいAPIと古いAPIの両方を自由に混在させるドライバーで作業していると仮定するのは間違いです。
  4. このチュートリアルは、どのバージョンでも古いAPIをまったくサポートしないOpenGL | ESなどのOpenGLの異なるエディション用です。

このようなものglBeginは、即時モードAPIと呼ばれることもあります。OpenGLには保持モードがあり、「イミディエートモード」には既にグラフィックスで別の定義があったため、これは非常に混乱しています。OpenGL 2.1以降廃止されているため、これらを単にOpenGL 1.x APIと呼ぶ方がはるかに優れています。

OpenGLの1.x APIは、昔は頂点をグラフィックスパイプラインにすぐに送信していました。これは、頂点をレンダリングするハードウェアの速度が、頂点データを生成するCPUの速度とほぼ同等の場合にうまく機能しました。当時のOpenGLは、三角形のラスタライズをオフロードしただけで、それ以外のことはほとんどしませんでした。

最近、GPUは高度な頂点およびピクセル変換を実行しながら、非常に高速で膨大な数の頂点を噛み砕くことができ、CPUは単純にリモートで追いつくことさえできません。さらに、CPUとGPUの間のインターフェイスはこの速度の違いを考慮して設計されているため、頂点を一度に1つずつGPUに送信することさえできません。

すべてのGLドライバーはglBegin、内部で頂点バッファーを割り当て、サブミットさglVertexれた頂点をこのバッファーに入れてから、呼び出されたときに単一の描画呼び出しでそのバッファー全体をサブミットすることによってエミュレートする必要がありglEndます。これらの関数のオーバーヘッドは、頂点バッファーを自分で更新した場合よりもはるかに大きいため、一部のドキュメントでは(非常に誤って)頂点バッファーを「最適化」と呼びます(最適化ではありません。実際に唯一の方法です) GPUと話す)。

OpenGLでは、長年にわたって非推奨または廃止されたさまざまなAPIがあります。いわゆる固定機能パイプラインもそのような要素です。一部のドキュメントでは、引き続きこのパイプラインを使用するか、プログラム可能なパイプラインと組み合わせます。固定機能パイプラインは、グラフィックカードが3Dシーンのレンダリングに使用されるすべての数学をハードコーディングし、OpenGL APIがその数学の構成値の設定に制限されていた昔からのものです。最近では、ハードウェアにはハードコーディングされた数学がほとんどなく、(CPUと同じように)ユーザー提供のプログラム(シェーダーと呼ばれることも多い)を代わりに実行します。

ここでも、固定機能機能がハードウェア上に存在しないため、ドライバーは古いAPIをエミュレートする必要があります。つまり、ドライバーには、独自のシェーダーを提供しない場合に使用される固定機能日からの古い数学を実行する多数の互換性シェーダーが組み込まれています。その古い固定関数状態を変更する古いOpenGL関数(古いOpenGLライティングAPIなど)は、実際には均一バッファーなどの最新のOpenGL機能を使用して、これらの値をドライバーの互換性シェーダーに供給しています。

互換性をサポートするドライバーは、これらの廃止された機能を使用し、それらを最新の機能とスムーズに組み合わせることができることを確認するために、多くの舞台裏での作業を行う必要があります。これは、一部のドライバーが新しい機能を取得するためにコアプロファイルを有効にすることを強制する理由の1つです。同時に使用される古いAPIと新しいAPIの両方をサポートする必要がないため、ドライバーの内部が大幅に簡素化されます。

多くのドキュメントでは、簡単に使い始めることができるという理由だけで、古いAPIから始めることを推奨している場合があります。Direct3Dは、初心者向けにこの問題を解決しました。コンパニオンライブラリ(DirectX Tool Kit)を提供することで、よりシンプルな描画APIと事前に作成されたシェーダーを提供します。残念ながら、OpenGLコミュニティの大部分は初心者向けの互換性プロファイルに固執していますが、古いOpenGL APIと新しいAPIを混在させることができないシステムがあるため、問題があります。さまざまなレベルの機能とターゲットユースケースと言語を備えた新しいOpenGLでのシンプルなレンダリングのための非公式のライブラリとツールがあります(MonoGame たとえば.NETユーザーの場合)、ただし公式に承認されたものも広く同意されたものもありません。

あなたが見つけているドキュメントは、OpenGL向けではないかもしれませんが、他の同様のAPIの1つ向けかもしれません。OpenGL | ES 1.xには固定機能レンダリングがありましたが、頂点サブミット用のOpenGL 1.x APIはありませんでした。OpenGL | ES 2.x +およびWebGL 1+には固定機能機能がまったくなく、これらのAPIには後方互換性モードがありません。

これらのAPIは、メインのOpenGLと非常によく似ています。それらは完全な互換性はありませんが、OpenGLの公式の拡張機能があり、一部の(すべてではない)ドライバーがOpenGL | ES(WebGLのベース)との互換性をサポートしています。以前は物事が十分に混乱していなかったからです。


4
+1素晴らしい回答!新しいOpenGLで簡単にレンダリングするための非公式のライブラリとツールをいくつか挙げることができたら素晴らしいと思います:)
Mehrdad

2
素晴らしい答え。私は当時、DirectXでも同じ問題を抱えていました。OpenGLよりもずっと簡単ですが、保持/即時モードからシェーダーへの飛躍は巨大でした。幸いなことに、ドキュメントは(少なくともOpenGLの場合とは異なり)大いに役立ちましたが、「どのように照明を
つける

私はopengl-tutorial.orgの著者であり、Seanに同意します。APIは、主にパフォーマンス上の理由でこのように進化しました。
Calvin1602

トピックに関する非常に良い情報..
reynmar

1
@Mehrdad:私は頭の上のものを思い出しません。SDL2やSFMLのような単純化された2Dレンダリング、さまざまなシーングラフライブラリ、MonoGame for C#などを追加するライブラリがありますが、Direct TKに直接相当するものについては今考えていません。「多く」と言うのは大きなうそであるかもしれないので、投稿を編集します。:)
ショーン・ミドルディッチ

9

主な違いは、戦略の最新性です。最初のチュートリアルで使用した即時モード:

glBegin(GL_QUADS);
    glColor3f(1, 0, 0); glVertex3f(0, 0, 0);
    glColor3f(1, 1, 0); glVertex3f(100, 0, 0);
    glColor3f(1, 0, 1); glVertex3f(100, 100, 0);
    glColor3f(1, 1, 1); glVertex3f(0, 100, 0);
glEnd();

古いため、新しいバージョンではサポートされていません。

OpenGLでレンダリングする現在の方法は、頂点バッファーとシェーダーを使用することです。もっと複雑に見えるかもしれませんが、パフォーマンスはかなり良くなっています。また、サポートコードでOpenGLをまとめたら、ほとんどの部分で違いが抽象化されます。


2

他の優れた回答にさらにコンテキストを追加するためです。

最初のリンクで説明したイミディエイトモードは、他の人が言ったように、OpenGL(1.1)の最も古いバージョンのレガシーコードです。GPUがトライアングルラスタライザーにすぎず、プログラム可能なパイプラインという概念が存在しなかったときに使用されていました。たとえば、GLQuakeやQuake 2のような初期のハードウェアアクセラレーションゲームのソースコードを見ると、即時モードが使用されていることがわかります。簡単に言えば、CPUは頂点の命令を一度に1つずつGPUに送信して、画面上に三角形の描画を開始します。レコードの場合、GL_QUADSはGL_TRIANGLESと同じ結果になりますが、GPUはそれらの四角形をその場で三角形に変換する必要があります。

モダン(3.2以降)OpenGLは異なるアプローチを採用しています。頂点データをGPUメモリにバッファリングしてすばやくアクセスし、glDrawArraysまたはglDrawElementsを使用して描画命令を送信できます。また、GPUが頂点を配置し、色を付ける方法をカスタマイズできるプログラム可能なパイプライン(glUseProgram)もあります。

即時モードが非推奨になった理由はいくつかありますが、主な理由はパフォーマンスです。Seanが答えで言ったように、今日では、GPUはCPUがアップロードできるよりも速くデータを処理できるため、GPUパフォーマンスのボトルネックになります。OpenGLを呼び出すたびに小さなオーバーヘッドが発生しますが、それはごくわずかですが、フレームごとに何万もの呼び出しを行うとスタックし始めます。簡単に言えば、イミディエイトモードを使用してテクスチャモデルを描画するには、フレームごとに頂点(glTexCoord2fおよびglVertex3f)ごとに少なくとも2つの呼び出しが必要です。最新のOpenGLでは、開始時に2、3の呼び出しを使用してデータをバッファリングし、頂点の数に関係なく、モデル全体を描画し、頂点配列オブジェクトをバインドするいくつかの呼び出しを使用して、いくつかの属性ポインターを有効にし、次に、glDrawElementsまたはglDrawArraysを1回呼び出します。

どのテクニックが正しいですか?まあそれはあなたがやろうとしていることに依存します。派手な後処理技術やシェーダーを必要としないシンプルな2Dゲームは、イミディエイトモードを使用すると問題なく動作し、おそらくコードの記述が簡単になります。ただし、より現代的な3Dゲームは本当に苦労します。GLSL(シェーダー言語)の学習を計画しているなら、間違いなく現代のテクニックを学んでください。

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