2012-01-02 11 views
86

ちょうど(私は、チャットSOに尋ねると思いますが、それはそこで死んだ!)私はこれを正しく理解しておくようにしたい:glVertexAttribPointerは明確

我々は、我々がすることによって、「現在」にする頂点配列を、持っていますそれを結合
その後、我々は
は、その後、我々は、本質的にその標的に結合したものは何でも移入ターゲットを経由してglBufferData は、私たちのバッファ
すなわちことを記入し、標的に結合し、その後、我々は説明しglVertexAttribPointerを呼び出すバッファを、持っていますデータがどのようにレイアウトされているか - データはバインドされているものであればGL_ARRAY_BUFFER とt彼の記述子は元の頂点配列に保存されます

(1)私の理解は正しいですか?
documentationは、すべてがどのように相関しているか少し不安です。

(2)デフォルトのVertex Arrayはありますか?私はglGenVertexArraysglBindVertexArrayを忘れてしまったので、私のプログラムは問題なく動作しました。


編集:私はステップ... glEnableVertexAttribArrayを逃しました。

(3)頂点Attribには時間glVertexAttribPointerで頂点配列に結合されているが呼び出され、その後、我々は頂点配列が現在バインドされているにかかわらず、そのうちの任意の時点でglEnableVertexAttribArrayを経由してそのATTRIBを有効/無効にすることができますか?

または(3b)の頂点Attribには時間glEnableVertexAttribArrayで頂点配列に結合されているが、異なる頂点配列が結合しているとき、呼ばれ、したがって、我々は、異なる時間にglEnableVertexAttribArrayを呼び出すことによって、複数の頂点配列に同じ頂点Attribにを追加することができます?

答えて

195

用語のいくつかは、ビットをオフになっている。

  • Vertex Arrayは単なる配列である(典型的にはfloat[])頂点データを含みます。それは何にも束縛される必要はありません。私は短いため、後で
  • Buffer Object、頂点を格納するとき、一般的にVertex Buffer Objectと呼ばれる、またはVBOを越えるだろうVertex Array ObjectまたはVAO、と混同してはならない、あなただけのBufferを呼んでいるものです。
  • glVertexAttribPointerは、glVertexPointerまたはglTexCoordPointerのように正確に機能しません。名前付き属性の代わりに、独自の属性を指定する番号を指定します。この値はindexとして渡します。次回のglDrawArraysまたはglDrawElementsを呼び出したときに、すべてのglVertexAttribPointerコールがキューに入れられます。 VAOがバインドされている場合、VAOはすべての属性の設定を保存します。

ここでの主な問題は、頂点属性をVAOと混同していることです。頂点属性は、描画のための頂点、テクスチャ、法線などを定義する新しい方法です。 VAOは状態を格納します。私が最初にあなたがメソッドの数がVAOsで呼び出しを削減する方法を説明し、その後、描画が頂点属性をどのように動作するかを説明するつもりです:

  1. あなたがシェーダでそれを使用する前に、属性を有効にする必要があります。たとえば、シェーダに頂点を送る場合は、最初の属性0として送信することになります。レンダーする前に、glEnableVertexAttribArray(0);で有効にする必要があります。
  2. 属性が有効になったので、使用するデータを定義する必要があります。これを行うには、VBO-glBindBuffer(GL_ARRAY_BUFFER, myBuffer);をバインドする必要があります。
  3. これで属性-を定義できます。パラメータの順番:0は定義する属性、3は各頂点のサイズ、GL_FLOATはタイプ、GL_FALSEは各頂点を正規化しないことを意味し、最後の2つのゼロは頂点にストライドまたはオフセットがないことを意味します。
  4. それで何か描く - であることglDisableVertexAttribArray(0);

ラップ - あなたが描く、次のものが属性0(現実的にそれはしますが、これは一例です)ので、我々はそれを無効にすることができますを使用することはできませんglDrawArrays(GL_TRIANGLES, 0, 6);

  • glUseProgram()が呼び出され、シェーダで適切に動作するレンダリングシステムがあります。しかし、5つの属性、頂点、テクスチャ、法線、色、およびライトマップの座標があるとしましょう。まず、これらの属性ごとに単一のglVertexAttribPointer呼び出しを行い、すべての属性を事前に有効にする必要があります。私がそれらをリストしたので、属性0-4を定義するとしましょう。 、その後、あなたは5を作成する必要があり

    for (int i = 0; i < 5; i++) 
        glEnableVertexAttribArray(i); 
    

    をそして、あなたは(あなたが1 VBOと使用オフセット/ストライドですべてを保存していない限り)属性ごとに異なるVBOsをバインドする必要があります:あなたはそうのようにそれらのすべてを可能にします異なるglVertexAttribPointerコール、glVertexAttribPointer(0,...);からglVertexAttribPointer(4,...);へ、頂点からライトマップ座標それぞれです。

    このシステムだけでは意味がありません。今度はVAOに移り、このタイプのレンダリングを行うときにメソッドコールの数を減らす方法を説明します。 VAOを使用する必要はありません。

    Vertex Array ObjectまたはVAOを使用して、glVertexAttribPointerコールのそれぞれを対象にしたすべてのglVertexAttribPointerコールとVBOの状態を保存します。

    glGenVertexArraysを呼び出して生成します。必要なものすべてをVAOに保存するには、glBindVertexArray でバインドしてから、完全描画呼び出し を実行します。 のバインドコールはすべて傍受され、VAOによって格納されます。あなたはちょうどそのglDrawArraysを呼び出すglBindVertexArrayでVAOをバインドする必要があり、あなたがオブジェクトを描画するときに今、あなたはVBOはglVertexAttribPointerのコールを結合したり、すべての再コールする必要はありませんglBindVertexArray(0);

    でVAOをアンバインドすることができますまたはglDrawElementsであり、これらのメソッド呼び出しをすべて作成していたのとまったく同じことが描画されます。あとでVAOのバインドも解除したいと思うかもしれません。

    VAOのバインドを解除すると、すべての状態は、VAOをバインドする前の状態に戻ります。 VAOがバインドされている間に行った変更があるかどうかはわかりませんが、テストプログラムで簡単に把握できます。誰かが私の注意に実際の描画呼び出しの必要性をもたらした:私は更新


    ...あなたは「デフォルト」VAOに結合するようglBindVertexArray(0);と考えることができますね。結局のところ、VAOをセットアップするときには実際には完全な描画呼び出しを行う必要はなく、すべてのバインディング作業だけです。なぜ以前に必要だと思ったのかわからないが、今修正されている。

  • +9

    「頂点バッファオブジェクトまたはVBO(時には単なるバッファオブジェクトとも呼ばれる)」実際に呼び出されるのは「時々」と呼ばれることがあります。これは単なるバッファオブジェクトであり、均一ブロック、ピクセル転送、トランスフォームフィードバック、またはその他の用途に使用できる他のバッファオブジェクトとは異なります。 OpenGL spec * never *は、「頂点バッファオブジェクト」として何も参照しません。 [元の拡張仕様](http://www.opengl.org/registry/specs/ARB/vertex_buffer_object.txt)でさえもそれを呼び出すことはありません。 –

    +0

    適切な名前付けに合わせて編集しました。ありがとうございます。 –

    +3

    優れた答え。これを書き留める時間をとってくれてありがとう!しかし、(1)レンダリングする前に、属性を定義する前に、glEnableVertexAttribArray(0)で有効にする必要があります。 glVertexAttribPointer'?私のテストでは、注文は問題にはならない。 (2)私があなたを正しく理解している場合、Vertex Attributesはグローバルで、有効/無効状態のみが現在バインドされているVAOに保存されますか? – mpen

    2

    呼び出されるAPIの用語とシーケンスは実際にはかなり混乱しています。バッファ、ジェネリックな頂点属性、およびシェーダ属性変数がどのように関連づけられるかは、さらに混乱するものです。かなり良い説明については、OpenGL-Terminologyを参照してください。

    さらに、リンクOpenGL-VBO,shader,VAOは、必要なAPI呼び出しを含む簡単な例を示しています。これは、即時モードからプログラム可能なパイプラインに移行する人にとっては特に良いことです。

    希望します。

    編集:以下のコメントからわかるように、人々は前提をして結論に飛びつくことができます。現実は初心者にとってはかなり混乱しているということです。

    +0

    "* 1分未満で見ても、誤った情報が1つ見つかりました:"これらは一般的な頂点属性で置き換えられます。インデックス)を、属性を処理するシェーダ変数(座標、色など)に関連付けます。彼らは「指数」と呼ばれていません。彼らは「場所」です。これは非常に重要な違いです。なぜなら、頂点属性[*も*は "インデックス"](https://www.opengl.org/wiki/Program_Introspection#Attributes)です。それは非常にひどいウェブサイトです。 –

    +1

    これは公正なコメントですが、完全に正確ではありません。 OpenGL APIを参照して汎用属性[glVertexAttribPointer](https://www.opengl.org/sdk/docs/man/html/glVertexAttribPointer.xhtml)を定義すると、 'void glVertexAttribPointer(GLuint index、GLint size、GLenum GLboize stride、const GLvoid * pointer) 'の場合、識別子は' index'と呼ばれます。プログラムの文脈で同じ識別子はAPI [glGetAttribLocation](https://www.opengl.org/sdk/docs/man/html/glGetAttribLocation.xhtml)の 'location'と呼ばれます。 –