1. ホーム
  2. c++

[解決済み] glBindVertexArraysとglBindBufferの役割とその関係とは?

2023-08-12 01:43:55

質問

私はOpenGLとグラフィックスプログラミングの初心者です。私は、これまで本当に徹底的でよく書かれている教科書を読んできました。しかし、私はよく理解していないコードでポイントにヒットし、私は先に進む前にこれらの行の意味を理解したいと思います。

GLuint abuffer;

glGenVertexArrays(1, &abuffer);
glBindVertexArray(abuffer);


GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

この本の説明では、最初の3行は 頂点配列オブジェクト を作成しており、これは関連するデータを頂点配列にバンドルするために使用されます。2行目では、未使用の名前(私は、符号なし整数の識別子を abuffer に格納されている符号なし整数の識別子と推測されます)、3行目でオブジェクトを作成し、アクティブにしています。

この本の説明では、4~7行目のcreating a バッファオブジェクト を作成し、5 行目で未使用の識別子 (頂点配列オブジェクトの 2 行目と同様?) を与え、6 行目でバッファを作成し、7 行目で CPU に十分なメモリを割り当て、データ (ポイント) へのポインタを作成することにより GL_STATIC_DRAW .

オブジェクトがアクティブになるとはどういうことでしょうか?その後、どのような場合に abuffer ? 頂点配列が関連データを束ねるとはどういうことか、そしてそのデータがこの頂点配列オブジェクトに関連付けられたのはいつなのか?

の関係で混乱しています。 abufferbuffer . 頂点配列とバッファオブジェクトの関係はどうなっているのか、どの時点でその関係が形成されるのか、混乱しています。実際に関係があるのかどうかは分かりませんが、教科書の中では、この2つの関係は直後に示されています。

どんな助けでも感謝します。ありがとうございます。

どのように解決するのですか?

低レベルの観点から、配列は2つの部分から構成されていると考えることができます。

  • 配列のサイズ、形状、およびタイプに関する情報 (たとえば、32 ビット浮動小数点数、それぞれが 4 つの要素を持つベクターの行を含む)。

  • バイトの大きな塊に過ぎない配列データ。

低レベルの概念はほとんど変わらないにもかかわらず、配列を指定する方法は何年も前から何度も変更されています。

OpenGL 3.0 / ARB_vertex_array_object

これは おそらく であるべきです。 OpenGL 3.xを動かせないのに、あなたのソフトウェアにお金をかけてくれる人がいるのは非常に稀です。

OpenGLのバッファ・オブジェクトはビットの大きな塊です。 アクティブバッファを単なるグローバル変数と考え、パラメータを使用する代わりにアクティブバッファを使用する関数の束があります。 これらのグローバルな状態変数はOpenGLの醜い側面です(以下に説明する直接状態アクセス以前)。 直接状態へのアクセスは後述します)。

GLuint buffer;

// Generate a name for a new buffer.
// e.g. buffer = 2
glGenBuffers(1, &buffer);

// Make the new buffer active, creating it if necessary.
// Kind of like:
// if (opengl->buffers[buffer] == null)
//     opengl->buffers[buffer] = new Buffer()
// opengl->current_array_buffer = opengl->buffers[buffer]
glBindBuffer(GL_ARRAY_BUFFER, buffer);

// Upload a bunch of data into the active array buffer
// Kind of like:
// opengl->current_array_buffer->data = new byte[sizeof(points)]
// memcpy(opengl->current_array_buffer->data, points, sizeof(points))
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

さて、典型的なバーテックスシェーダは 頂点 を入力として受け取りますが、ビットの大きな塊ではありません。 そこで、ビットの塊(バッファ)をどのように頂点にデコードするかを指定する必要があります。 それが配列の仕事です。 同様に、quot;active"という配列があり、これは単なるグローバル変数と考えることができます。

GLuint array;
// Generate a name for a new array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Make the buffer the active array buffer.
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Attach the active buffer to the active array,
// as an array of vectors with 4 floats each.
// Kind of like:
// opengl->current_vertex_array->attributes[attr] = {
//     type = GL_FLOAT,
//     size = 4,
//     data = opengl->current_array_buffer
// }
glVertexAttribPointer(attr, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Enable the vertex attribute
glEnableVertexAttribArray(attr);

OpenGL 2.0 (古い方法)

OpenGL 2.xでは、頂点配列はなく、データは単なるグローバルなものでした。 あなたはまだ glVertexAttribPointer()glEnableVertexAttribArray() と呼ぶ必要がありましたが 毎回 を呼び出す必要がありました。 OpenGL 3.xでは、配列を一度セットアップするだけです。

OpenGL 1.5に戻ると、実際にバッファを使うことができましたが、それぞれの種類のデータを結合するために別の関数を使用しました。 例えば glVertexPointer() は頂点データ用で glNormalPointer() は通常のデータ用でした。 OpenGL 1.5以前は、バッファはありませんでしたが、アプリケーションのメモリへのポインタを使用することができました。

OpenGL 4.3 / ARB_vertex_attrib_binding(頂点属性バインディング

4.3では、またはARB_vertex_attrib_binding拡張があれば、属性フォーマットと属性データを別々に指定することができます。 これは、1つの頂点配列を異なるバッファ間で簡単に切り替えることができるため、素晴らしいことです。

GLuint array;
// Generate a name for a new array array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Enable my attributes
glEnableVertexAttribArray(loc_attrib);
glEnableVertexAttribArray(normal_attrib);
glEnableVertexAttribArray(texcoord_attrib);
// Set up the formats for my attributes
glVertexAttribFormat(loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribFormat(normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexAttribFormat(texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexAttribBinding(loc_attrib,      0);
glVertexAttribBinding(normal_attrib,   0);
glVertexAttribBinding(texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
// This replaces several calls to glVertexAttribPointer()
// Note: you don't need to bind the buffer first!  Nice!
glBindVertexBuffer(0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glBindVertexBuffer(0, buffer2, 0, 32);

OpenGL 4.5 / ARB_direct_state_access

OpenGL 4.5では、あるいはARB_direct_state_access拡張がある場合、もはや glBindBuffer() または glBindVertexArray() というように、配列とバッファを直接指定します。 最後に配列をバインドするだけで、描画されます。

GLuint array;
// Generate a name for the array and create it.
// Note that glGenVertexArrays() won't work here.
glCreateVertexArrays(1, &array);
// Instead of binding it, we pass it to the functions below.

// Enable my attributes
glEnableVertexArrayAttrib(array, loc_attrib);
glEnableVertexArrayAttrib(array, normal_attrib);
glEnableVertexArrayAttrib(array, texcoord_attrib);
// Set up the formats for my attributes
glVertexArrayAttribFormat(array, loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(array, normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexArrayAttribFormat(array, texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexArrayAttribBinding(array, loc_attrib,      0);
glVertexArrayAttribBinding(array, normal_attrib,   0);
glVertexArrayAttribBinding(array, texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
glVertexArrayVertexBuffer(array, 0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glVertexArrayVertexBuffer(array, 0, buffer2, 0, 32);

// You still have to bind the array to draw.
glBindVertexArray(array);
glDrawArrays(...);

ARB_direct_state_accessは多くの理由のために素晴らしいです。 OpenGLが追跡している隠されたグローバル変数について考える必要がないように、配列とバッファのバインディングについて忘れることができます(描画するときを除く)。 オブジェクトの名前を生成することと、オブジェクトを生成することの違いを忘れることができます。 glCreateBuffer()glCreateArray() は両方を同時に実行します。

Vulkan

Vulkanはさらに進んで、上に書いた擬似コードのようなコードを書かせます。 つまり、次のようなものが出てきます。

// This defines part of a "vertex array", sort of
VkVertexInputAttributeDescription attrib[3];
attrib[0].location = 0; // Feed data into shader input #0
attrib[0].binding = 0;  // Get data from buffer bound to slot #0
attrib[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attrib[0].offset = 0;
// repeat for attrib[1], attrib[2]