将 VAO 与 glDrawElements 结合使用
Using VAO with glDrawElements
我正在尝试(第一次)使用 OpenGL 3.2 在屏幕上绘制一些精灵。我正在尝试设置一个 VAO,但它不起作用。我在调用 glDrawElements 时收到 EXC_BAD_ACCESS。
VAO 设置:
// setting up VAO
glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
glGenBuffers(1, &indices_id_);
glGenBuffers(1, &attributes_id_);
glBindBuffer(GL_ARRAY_BUFFER, attributes_id_);
constexpr GLfloat* ptr = 0;
::glVertexAttribPointer(attribute_position_, 2, GL_FLOAT, false, STRIDE, ptr);
::glVertexAttribPointer(attribute_region_, 2, GL_FLOAT, false, STRIDE, ptr + 2);
::glVertexAttribPointer(attribute_color_, 4, GL_FLOAT, false, STRIDE, ptr + 4);
::glEnableVertexAttribArray(attribute_position_);
::glEnableVertexAttribArray(attribute_region_);
::glEnableVertexAttribArray(attribute_color_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_id_);
{
auto data = std::make_unique<short[]>(BATCH_SIZE * 6);
short j = 0;
for (std::size_t i = 0; i < BATCH_SIZE * 6; i += 6, j += 4)
{
data[i] = j;
data[i + 1] = (short)(j + 1);
data[i + 2] = (short)(j + 2);
data[i + 3] = (short)(j + 2);
data[i + 4] = (short)(j + 3);
data[i + 5] = j;
}
glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLsizeiptr>(BATCH_SIZE * 6 * sizeof(short)), data.get(), GL_STATIC_DRAW);
}
glBindVertexArray(0);
然后在绘图循环的其他地方:
// drawing
glBindVertexArray(vao_);
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(float) * buffer_index_), attributes_.data(), GL_DYNAMIC_DRAW);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(6 * number_of_sprites_), GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
谁能看出我做错了什么?
更新
我已经添加了建议的更改(非常感谢)。但是,我现在发现我需要在绘图时在 glBindVertexArray(vao_);
之前添加对 glBindBuffer(GL_ARRAY_BUFFER, attributes_id_);
的调用以消除 EXC_BAD_ACCESS 错误。
glBufferData()
期望目标缓冲区作为第一个参数。这里的命名有点混乱,但这意味着您告诉 OpenGL 您指的是哪个绑定缓冲区,而不是缓冲区的 name
。这是一个例子:
glBindBuffer(GL_ARRAY_BUFFER, foo); // Binds the buffer named foo to the GL_ARRAY_BUFFER target
glBufferData(GL_ARRAY_BUFFER, ...); // Tells GL you mean the buffer bound to the GL_ARRAY_BUFFER target
OpenGL 4.6 API Core Profile Specification; 10.3. VERTEX ARRAYS; page 347
A vertex array object is created by binding a name returned by GenVertexArrays
with the command
void BindVertexArray( uint array );
array is the vertex array object name. The resulting vertex array object is a new state vector, comprising all the state and with the same initial values listed in tables
23.4- 23.7.
Table 23.4 包含 ELEMENT_ARRAY_BUFFER_BINDING
这意味着,绑定 ELEMENT_ARRAY_BUFFER 的状态存储在 Vertex Array Object.
中
在你的情况下 indices_id_
存储在 vao_
的状态向量中,因为
glBindVertexArray(vao_);
.....
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_id_);
当你打电话时
glBindVertexArray(0);
那么indices_id_
不再在当前状态向量中。
您必须更改指令的顺序:
glBindVertexArray(vao_);
.....
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_id_);
{
.....
glBufferData(indices_id_, static_cast<GLsizeiptr>(BATCH_SIZE * 6), data.get(), GL_STATIC_DRAW);
}
glBindVertexArray(0);
我正在尝试(第一次)使用 OpenGL 3.2 在屏幕上绘制一些精灵。我正在尝试设置一个 VAO,但它不起作用。我在调用 glDrawElements 时收到 EXC_BAD_ACCESS。
VAO 设置:
// setting up VAO
glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
glGenBuffers(1, &indices_id_);
glGenBuffers(1, &attributes_id_);
glBindBuffer(GL_ARRAY_BUFFER, attributes_id_);
constexpr GLfloat* ptr = 0;
::glVertexAttribPointer(attribute_position_, 2, GL_FLOAT, false, STRIDE, ptr);
::glVertexAttribPointer(attribute_region_, 2, GL_FLOAT, false, STRIDE, ptr + 2);
::glVertexAttribPointer(attribute_color_, 4, GL_FLOAT, false, STRIDE, ptr + 4);
::glEnableVertexAttribArray(attribute_position_);
::glEnableVertexAttribArray(attribute_region_);
::glEnableVertexAttribArray(attribute_color_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_id_);
{
auto data = std::make_unique<short[]>(BATCH_SIZE * 6);
short j = 0;
for (std::size_t i = 0; i < BATCH_SIZE * 6; i += 6, j += 4)
{
data[i] = j;
data[i + 1] = (short)(j + 1);
data[i + 2] = (short)(j + 2);
data[i + 3] = (short)(j + 2);
data[i + 4] = (short)(j + 3);
data[i + 5] = j;
}
glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLsizeiptr>(BATCH_SIZE * 6 * sizeof(short)), data.get(), GL_STATIC_DRAW);
}
glBindVertexArray(0);
然后在绘图循环的其他地方:
// drawing
glBindVertexArray(vao_);
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(float) * buffer_index_), attributes_.data(), GL_DYNAMIC_DRAW);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(6 * number_of_sprites_), GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
谁能看出我做错了什么?
更新
我已经添加了建议的更改(非常感谢)。但是,我现在发现我需要在绘图时在 glBindVertexArray(vao_);
之前添加对 glBindBuffer(GL_ARRAY_BUFFER, attributes_id_);
的调用以消除 EXC_BAD_ACCESS 错误。
glBufferData()
期望目标缓冲区作为第一个参数。这里的命名有点混乱,但这意味着您告诉 OpenGL 您指的是哪个绑定缓冲区,而不是缓冲区的 name
。这是一个例子:
glBindBuffer(GL_ARRAY_BUFFER, foo); // Binds the buffer named foo to the GL_ARRAY_BUFFER target
glBufferData(GL_ARRAY_BUFFER, ...); // Tells GL you mean the buffer bound to the GL_ARRAY_BUFFER target
OpenGL 4.6 API Core Profile Specification; 10.3. VERTEX ARRAYS; page 347
A vertex array object is created by binding a name returned by GenVertexArrays with the command
void BindVertexArray( uint array );
array is the vertex array object name. The resulting vertex array object is a new state vector, comprising all the state and with the same initial values listed in tables 23.4- 23.7.
Table 23.4 包含 ELEMENT_ARRAY_BUFFER_BINDING
这意味着,绑定 ELEMENT_ARRAY_BUFFER 的状态存储在 Vertex Array Object.
在你的情况下 indices_id_
存储在 vao_
的状态向量中,因为
glBindVertexArray(vao_);
.....
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_id_);
当你打电话时
glBindVertexArray(0);
那么indices_id_
不再在当前状态向量中。
您必须更改指令的顺序:
glBindVertexArray(vao_);
.....
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_id_);
{
.....
glBufferData(indices_id_, static_cast<GLsizeiptr>(BATCH_SIZE * 6), data.get(), GL_STATIC_DRAW);
}
glBindVertexArray(0);