OpenGLシェーダーの明示的vs自動属性ロケーションバインディング


83

OpenGLシェーダープログラムの属性の場所を設定するとき、2つのオプションに直面します。

リンクする前のglBindAttribLocation()は、属性の場所を明示的に定義します。

または

リンク後のglGetAttribLocation()は、自動的に割り当てられた属性の場所を取得します。

どちらか一方を使用するためのユーティリティは何ですか?

そして、もしあれば、どれが実際に好まれますか?


6
glBindAttribLocationLinuxでうまく機能するグラフィックエンジンをわざわざ使用することはありませんでした。Windowsに移植したとき、法線を頂点として使用していました。シェーダーを機能glBindAttribLocationさせるには、シェーダー内の変数の順序を明示的に指定する必要がありました...
Jarrett

回答:


93

明示的な場所の定義を好む理由の1つを知っています。

ジオメトリデータを頂点配列オブジェクトに保持することを検討してください特定のオブジェクトに対して、インデックスが対応するようにVAOを作成します。次に例を示します。

  • インデックス0:位置、
  • インデックス1:法線、
  • インデックス2:texcoords

ここで、2つの異なるシェーダーを使用して1つのオブジェクトを描画するとします。1つのシェーダーは入力として位置と通常のデータを必要とし、もう1つは位置とテクスチャ座標を必要とします。

これらのシェーダーをコンパイルすると、最初のシェーダーは属性インデックス0の位置を期待し、法線は1を期待することに気付くでしょう。他のシェーダーは、0の位置を期待しますが、テクスチャ座標は1です。

https://www.opengl.org/wiki/Vertex_Shaderの引用:

自動割り当て

前の2つの方法のどちらも入力を属性インデックスに割り当てない場合、プログラムがリンクされると、インデックスはOpenGLによって自動的に割り当てられます。割り当てられるインデックスは完全に任意であり、まったく同じ頂点シェーダーコードを使用している場合でも、リンクされているプログラムごとに異なる場合があります。

これは、VAOを両方のシェーダーで使用できないことを意味します。たとえば、オブジェクトごとに1つのVAOを使用する代わりに、最悪の場合、シェーダーごとにオブジェクトごとに個別のVAOが必要になります。

を介してシェーダーに独自の属性番号付け規則を使用させると、glBindAttribLocationこの問題を簡単に解決できます。必要なのは、属性とその確立されたIDの間の一貫した関係を維持し、リンク時にシェーダーにその規則を使用するように強制することです。

(個別のVAOを使用しない場合、これはそれほど大きな問題ではありませんが、コードがより明確になる可能性があります。)


ところで:

OpenGLシェーダープログラムの属性の場所を設定するとき、2つのオプションに直面します

OpenGL / GLSL 3.3には3番目のオプションがあります:シェーダーコードで直接場所を指定します。次のようになります。

layout(location=0) in vec4 position;

ただし、これはGLSLESシェーダー言語にはありません。


1
要点がわかりません。VAOは非常に軽量で、通常はフレームごとに再作成します。あなたの場合、各シェーダーを呼び出す前に、異なるVAOを作成するだけですよね。
PierreBdR 2012年

1
はい、もちろんできます。これも同様に機能します。ここでは、規則についてのみ説明します。:)
コス2012年

4
3番目のオプションは実際にはGLES2.0で使用できますが、形式は少し異なります。layout(location = 0)attribute vec4 position; GLSLファイルの先頭にもこれが必要であることに注意してください。#extension GL_EXT_separate_shader_objects:enable
Gavin Maclean

35
「VAOは非常に軽量で、通常はフレームごとに再作成します。あなたの場合、各シェーダーを呼び出す前に、異なるVAOを作成するだけですよね?」-いいえ、通常これを行うことはありません。これは、最終的にVAOの目的全体を完全に無効にするためです。では、なぜVAOを使用するのでしょうか。
クリスチャンラウ2013年

2
ただのメモ。ジオメトリデータをVAOに保持することはありません。それはVBOになります。VAOにはデータストレージがありません。
平均ジョー2015年

20

ここでのもう1つの答えは、glGetAttribLocationがデータを呼び出し元に返すことです。これは、パイプラインフラッシュが暗黙的に必要であることを意味します。プログラムをコンパイルした直後に呼び出すと、基本的に非同期コンパイルが同期的に行われるようになります。



おかげで、これは非常に重要な考慮事項です。
Jing

1
ほとんどの状況では、glGetUniformLocationとにかく電話する必要があると私は理解しています。この特定の考慮事項はまだ関連していますか?
マイクウィアー

@MikeWeir GL 4.3以降、明示的な均一位置を設定できます
ルスラン

1
@Ruslan彼らはOpenGLESを使用しています。
マイクウィアー

9

3番目のオプション、つまりlayout(location=0) in vec4 position;シェーダーコードは、OpenGL ES 3.0 / GLSL 300esで使用できるようになりました。ただし、頂点シェーダー入力変数の場合のみ。


7
彼らが示唆しているように、Intelカードはこれをサポートしていない可能性があります(それ以外の場合は完全に3.0以上準拠していますが)、これは嫌です:)
mlvljr 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.