OpenGLの「バッファ」と「配列」の違いは?


12

webGLまたはOpenGLでドキュメントを読むと、関数とオブジェクトの名前の使用方法にいくつかのパターンが見られます。しかし、バッファオブジェクトと配列の違いを理解できません。

「頂点バッファオブジェクト」、「頂点配列オブジェクト」、さらにある種の「バッファ配列」または「配列バッファ」があります。

OpenGLコンテキストでは、何かが「配列」であり、代わりに「バッファ」と呼ばれるべきときは?


いくつかの観点から、ネットワーク経由でデータを取得し、受信したすべてのログを保存することを考えてください。ソケットを読み取って、受け取ったデータをどこかに配置して、それを渡すことができるようにする必要があります。それがバッファーです。多くの場合、ローカルスコープの動的に割り当てられた単純なリストタイプです。時にはchar* buffer = socketRead();(擬似コード)と同じくらい簡単です。一方、ログはアプリのライフサイクル全体を通じて有効です。したがって、どこかで配列を作成し、ソケットの読み取りを開始します。データを取得するたびに、そのチャンクを配列に書き込み、受け取ったすべてのデータの適切なリストを提供します。
ケビン

回答:


5

頂点配列オブジェクトの命名は、やや不幸です。アプリケーションの中/と一緒に表示される(使用される)ものが3つあり、名前に「配列」または「バッファー」が付いている(歴史的に)名前が異なる(まあ、フレームバッファーオブジェクトもあります)しかし、私はそれを無視します)。

  1. 正式かつ事実上アプリケーションに存在するが、OpenGLによって一度にプルされるデータ(頂点ごとではなく)。これはかつて、頂点配列と呼ばれるものでした。
    この目的は、データが一貫しているという約束をしたときに、OpenGLが明確に定義された時点ですべてを一度にコピーし、AGPまたは1つのブロックに何でもプッシュできるため、アクセスをより効率的にすることでした。これはもう存在しません。
  2. 「バインド」できる、つまりアクティブにできるハンドルによって、データが隠されてアクセス可能になります。データ実際にはメインメモリまたはグラフィックカードに存在するか、PCIeマッピング可能な領域に移動されますが、正式に所有していない場合(物理的にRAMにあり、データがアプリケーションから来た場合でも) )それ-対応するAPIを介して現在「マッピング」していない限り、書き込み可能な(場合によっては読み取り可能な)ポインターを返します。また、データに何が起こるかを制御する能力にも制限があります(いくつかのヒントを与えることができますが、それはほとんどそれです)。
    OpenGLは、このデータを多かれ少なかれ自由に移動でき、対応するAPIを介してバッファにコピーしたり、バッファからコピーしたり、マップ中にデータにアクセスしたりすることのみ許可されます。これは、バッファオブジェクトと呼ばれるものです(頂点を含む場合は頂点バッファオブジェクトですが、実際には必要ありません。画像データやユニフォームでもかまいません。一度だけ、頂点のみが最初にサポートされました)。
    これの目的は、OpenGLが(原則として)必要なことを実行できることを保証することであり、描画する前に投機的にPCIeにバッファをプッシュすることさえできます。データを所有していないため(OpenGLはそうです!)、指定されたAPIを介してのみアクセスできるため、データが有効であることが常にわかっているため、これは機能します。ドライバは、何か別のメモリが必要な場合にグラフィックスカードのバッファメモリを破棄し、後で必要に応じてシークレットコピーから復元することもできます。
  3. より良い名前がbuffer-setまたはdescriptor-setのようなものになるような本当に愚かな誤称で、これは悪名高い頂点配列オブジェクトです。あなたの観点からは、別のあいまいなハンドル(バインドできる)の下にまとめられたバッファハンドルのセットにすぎません。それが起こると、現実はもう少し複雑です。実際、VAOは実際のハードウェアの動作に非常に近いものです。グラフィックカードには少数(多くの場合2、4、または8)の記述子セット(バッファーだけでなくサンプラー用)があり、それぞれにかなりのエントリがあり、非常に効率的に切り替えることができます。
    現在、頂点配列オブジェクトの目的は、API呼び出しの回数を減らし、OpenGLが内部で行う必要のある一貫性チェックの回数を減らすこと、そしてもちろんハードウェアをそのまま使用することです。5つのバッファをバインドする場合、各バッファはおそらく高価なチェックを通過する必要があり、各バッファはドライバのキャッシュミスの候補です。さらに、各バッファはグラフィックカードと通信して記述子などを変更する必要があります1つのVAOをバインドすると、ドライバーは(多くの場合)グラフィックスカードの記述子セットを簡単に切り替えることができます。

8

頂点配列オブジェクト(VAO)は、1つ以上の頂点バッファーオブジェクトを含むオブジェクトであり、レンダリングされたオブジェクト全体の情報を格納するように設計されています。

khronosから引き出された)

各バッファーは、頂点配列(オブジェクト)の1つの属性を構成する傾向があります。VAOには、多くの頂点属性(位置、色、UVなど)を含めることができます。それぞれが独自のバッファーに保持される場合があります。バッファーは、フォーマットされていない一連の連続したバイトを示し、CPU側のOpenGL呼び出しとGPU側のシェーダー作業の両方で、バッファー要素ごとにサイズ(タイプ)を明示的に指定する必要があります。

それが一つの方法です。これが機能する他の方法は次のとおりです。

  • すべての属性は、インターリーブされて単一のバッファーに格納されます、または
  • 一部の属性は独自の専用バッファーに存在し、他の属性はバッファーを共有します。

次の図は、後者の2つのケースを示しています。

ここに画像の説明を入力してください

結論:OpenGLで「頂点配列」という語句が非修飾で使用されている場合、それはVAOを意味すると想定できます。VAOは、OpenGLコンテキストでは(具体的には)バッファとはまったく異なるものです。

コメントを編集:GL_ARRAY_BUFFER上記のように、頂点属性データにそのバッファオブジェクトを使用する意図を示します。これは、バッファが頂点属性のみに使用されないためです。ただし、これは最も一般的なユースケースであり、VAOについて質問しているため、他のものには触れません。ただし、ここに設定可能な他のタイプのバッファのリストがあります。


したがって、バッファは次のとおりです。1。GPUに常駐している、2。ほとんどの場合、1種類のデータ(頂点のみ、カラーectのみ)、3。データはインターリーブされている、つまり111122223333 ect 4. データにアクセスする方法提供しません(buffer [2]またはbuffer [vertex_3434]ではありません)現在、配列は次のとおりです。 、要素のサイズ、オフセット、バッファからのデータに正しくアクセスできるようになりました?
-coobit

1. バッファは両端に存在し、CPUとGPUの間で転送されます(場合によっては前後に)。そうでない場合、ディスクからメッシュをロードするときにGPUにアップロードするデータをどのように入力しますか。はい、要素はバッファ全体で統一された型ですが、使用している技術に応じて、各バッファ要素はプリミティブまたはstruct型のいずれかになります。データ、バッファごとにインターリーブされるか、完全に均一になる場合あります。CPUの従来のC配列と同様に、それらにインデックスを付けることができます。配列オブジェクト(この正しい用語を使用するか、自分自身を混乱させることになります!)...(以下に続く)
エンジニア

2.はい。インシェーダーバッファー宣言が、CPU側のVAOで設定した仕様と一致することを明示的に確認する必要があります。「頂点プロセッサで使用されるデータの定義に関連するすべての状態は、頂点にカプセル化されます配列オブジェクト。」(クロノスドキュメント)
エンジニア

だから、ただもっと釘を打つために... AOの前にBOだけを使って人々はどのように働いていましたか?または、AOは常にOpenGLに存在し、VBOの後に導入されたのはVAOだけですか?
coobit

@coobit io7m.com/documents/history-vertex-spec-これにより、固定パイプライン(旧式)OpenGL、3Dfxなどと最新のプログラム可能なパイプラインOpenGLおよびDirect3Dの違いがわかります。
エンジニア

5

この用語は、OpenGLの歴史に根ざしています。ここで重要なGLバージョンのほとんどについて、OpenGLは段階的に進化し、APIを変更するのではなく、既存のAPIに新しい機能を追加することで覚えておくことが重要です。

OpenGLの最初のバージョンには、これらのオブジェクトタイプはありませんでした。描画は、複数のglBegin / glEnd呼び出しを発行することで達成されましたが、このモデルの問題の1つは、関数呼び出しのオーバーヘッドの点で非常に効率が悪いことでした。

OpenGL 1.1は、頂点配列を導入することでこれに対処するための最初のステップを踏みました。頂点データを直接指定する代わりに、C / C ++配列からソースを取得できるようになりました-したがって、その名前です。したがって、頂点配列はまさにそれです-頂点の配列とそれらを指定するのに必要なGL状態。

次の大きな進化はGL 1.5によってもたらされ、頂点配列データをシステム(「クライアント側」)メモリではなくGPUメモリに保存できるようになりました。GL 1.1頂点配列仕様の弱点は、使用するたびに頂点データの完全なセットをGPUに転送する必要があることでした。GPU上に既に存在する場合、この転送は回避され、潜在的なパフォーマンスの向上が達成されます。

そのため、GPUにこのデータを保存できる新しいタイプのGLオブジェクトが作成されました。テクスチャオブジェクトがテクスチャデータの格納に使用されるように、頂点バッファオブジェクトは頂点データを格納します。これは、実際には、より一般的なバッファオブジェクトタイプの特殊なケースであり、非特定のデータを格納する場合があります。

頂点バッファーオブジェクトを使用するためのAPIは、既存の頂点配列APIに便乗しているため、バイトオフセットをポインターに変換するなどの奇妙なことがわかります。そのため、状態を保存するだけの頂点配列APIがあり、データはメモリ内配列ではなくバッファオブジェクトから取得されます。

これは私たちの物語の終わりにほとんど私たちをもたらします。結果のAPIは頂点配列状態を指定する際に非常に冗長であったため、最適化の別の手段は、この状態をすべて収集し、1回のAPI呼び出しで複数の頂点配列状態の変更を許可し、GPUを許可する新しいオブジェクトタイプを作成することでした事前にどの状態が使用されるかを知ることができるため、潜在的に最適化を実行します。

このすべてを一緒に収集する頂点配列オブジェクトを入力します。

要約すると、頂点配列は、描画のための状態とデータ(配列に格納されている)のコレクションとして始まりました。頂点バッファは残し、GLオブジェクトタイプのメモリ内のアレイ・ストレージを置き換える頂点配列だけの状態であることを。頂点配列オブジェクトは、それがより容易に変更し、より少ないAPI呼び出しとすることができるように、この状態のためだけコンテナオブジェクトです。


0

私はしばらくの間OpenGLで働いたことがないので、私は半分しか正しくないかもしれません。一般的に言って、バッファはフォーマットされていないメモリの配列を格納します。配列は、連続したメモリの一般的な用語です。

バッファはコンテキストにバインドする必要がありますが、配列は単なるデータの配列です。正しくリコールする場合、バッファ内のデータはグラフィックスカードにコピーされることを意味します(したがって、バインディング)。

これが少し役立つことを願って


GL_ARRAY_BUFFERとは何ですか?なぜそう呼ばれたのですか?あなたの仮説によると、それは「

さて、この特定の例は、(配列をバインドする)バッファーの単なるIDです。(例では)配列バッファーは頂点属性に使用されるため、基本的には頂点属性配列をバッファーにバインドします。わかりにくいので、例を挙げましょう。CPU側には、色、法線、位置などの配列がありますが、ここでGPUにアクセスさせます。つまり、bindBufferが入ってくると、基本的に「cpu-array」を「gpu-array」にマッピングします。
ジュース

なぜそう呼ばれたのか、私はそれに答えることができません。私はあなたがそこに行くの異なるデータの配列、色、通常、などを持っているので、それがあることを推測う
Juicef
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.