如何更新 VertexArrayBuffer 的内容

How do I update the contents of a VertexArrayBuffer

我创建了一个带有 2 个顶点数组缓冲区的 VAO。第一个缓冲区包含顶点的坐标,而第二个缓冲区包含每个顶点的 4 个数据值(类型 GLbyte)。

/*
** Create a VAO and bind it
*/
    glCreateVertexArrays(1, &vertex_array_object);
    glBindVertexArray(vertex_array_object);
/*
** Create a buffer and initilise it
*/
    glCreateBuffers(1, &vertex_buffer);
    glNamedBufferStorage(vertex_buffer, sizeof(verticies), verticies, 0);
/*
** Bind the buffer to the VAO
*/
    glVertexArrayVertexBuffer(vertex_array_object, 0, vertex_buffer, 0, sizeof(float)*3);
/*
** Specify the data format,  
*/
    glVertexArrayAttribFormat(vertex_array_object,0, 3, GL_FLOAT, GL_FALSE, 0);
/*
** Specify the vertex buffer binding for this attribute
*/
    glVertexArrayAttribBinding(vertex_array_object,0,0);
/*
** Enable the attribute
*/
    glEnableVertexArrayAttrib(vertex_array_object,0);

/*
** Now repeat for another buffer to hold per vertex data
**
** Create  and initilise it
*/
    glCreateBuffers(1, &nvd_buffer);
    glNamedBufferStorage(nvd_buffer, sizeof(vectors), vectors, 0);
/*
** Bind the buffer to the VAO
*/
    glVertexArrayVertexBuffer(vertex_array_object, 1, nvd_buffer, 0, sizeof(GLbyte)*4);
/*
** Specify the data format,  
*/
    glVertexArrayAttribFormat(vertex_array_object, 1, 4, GL_BYTE, GL_FALSE, 0);
/*
** Specify the vertex buffer binding for this attribute
*/
    glVertexArrayAttribBinding(vertex_array_object,1,1);
/*
** Enable the attribute
*/
    glEnableVertexArrayAttrib(vertex_array_object,1);

一切正常,我的顶点着色器可以访问第二个缓冲区中的数据并将其传递给几何着色器,在几何着色器中用于创建其他点。

稍后我想更新第二个缓冲区中的数据,但我不知道该怎么做。我想我应该使用

  glNamedBufferSubData(....)

但我不知道如何从 VAO 获取我需要输入到此函数中的缓冲区。我知道我可以存储分配给 "nvd_buffer" 的原始值,但是有没有办法直接从 VAO 获取此信息,因为我知道我用来将缓冲区绑定到 VAO

的绑定索引
glVertexArrayVertexBuffer(vertex_array_object, 1, nvd_buffer, 0, sizeof(GLbyte)*4);

您不应该询问 VAO 中存储了哪些缓冲区对象。这有很多原因。

  1. 在为 VAO 查询指定 DSA 函数时,出现了一个...问题。 The enumerators weren't actually specified to work for the DSA query functions correctly. 该问题已在规范中得到解决,但这并不意味着任何此类修复都过滤掉了实现了损坏的规范语言的实现。因此,对于任何此类查询是否会成功存在一些疑问。

  2. 您告诉 OpenGL 使用哪个缓冲区。因此,你已经知道答案了。没有理由问一个你已经知道答案的问题。如果您选择忘记答案,您也可以轻松地选择不忘记它。所以这是一个你已经有工具可以解决的问题,你不应该让 OpenGL 帮你解决。

  3. 您不应将缓冲区对象视为属于使用它们的 VAO。它们是它们自己的资源,应该与使用它们的任何 VAO 分开管理。事实上,大多数 VAO 用法(特别是使用单独的属性格式)将在整个渲染循环中将不同的缓冲区附加到 VAO。所以在那些情况下,缓冲区和使用它的 VAO 之间的链接是完全短暂的。

  4. 终身问题。如果在 VAO 未绑定到上下文时删除缓冲区对象名称,缓冲区对象将继续存在,直到它不再附加到任何 VAO。如果您从 VAO 查询缓冲区对象,那么您将有效地将名称带回 "life",但仍然会在此类缓冲区不再使用时消失。这可能会导致很难检测到的错误。所以如果你不从OpenGL查询名称,这种错误是不可能的。

综上所述,您要查找的函数是 glGetVertexArrayIndexediv。由于在撰写本文时文档尚未根据我在第 1 项中提到的错误修复进行更新,因此它不会告诉您使用正确的枚举器。所以查询看起来像这样:

GLuint buffer;
glGetVertexArrayIndexediv(vao, binding_index, GL_VERTEX_BINDING_BUFFER, reinterpret_cast<GLint*>(&buffer));

其中 binding_index 是您传递给 glVertexArrayVertexBuffer 的索引。


但是,这实际上不会使您的上传代码起作用。哦,是的,它会给你一个有效的缓冲区对象名称,但你不能上传到它。为什么?

因为你告诉 OpenGL 你不会。就在这里:

glNamedBufferStorage(vertex_buffer, sizeof(verticies), verticies, 0);

0 是您为刚刚创建的不可变存储缓冲区提供的使用标志。对于可变缓冲区,用法提示只是一个提示;它不会限制您使用它的能力。

这是不可变存储缓冲区的情况。如果您没有指定您将以某种方式操作 CPU 中的数据存储,那么您 不能 以这种方式操作它。所以如果你想在一个不可变的存储缓冲区上使用 glNamedBufferSubData,你 必须 告诉 OpenGL 你打算通过 providing the appropriate flag 来做到这一点。具体来说,GL_DYNAMIC_STORAGE_BIT.