获取制服块中制服的名称

Use*_*-92 1 c++ opengl buffer glsl

所以我问了这个问题:优化均匀传输,并建议使用均匀缓冲区。我做了一些研究并尝试实现它,但在从着色器加载统一块的格式时遇到了问题。在我的项目中,我有一个着色器类,它加载所有制服、顶点属性并将它们存储在着色器中,以便用户可以轻松更改值,而无需再次从着色器查询制服的位置。我正在尝试对统一块执行相同的操作,但我现在不知道如何检索我需要的所有数据。

这是我试图从着色器获取的数据类型:

  1. 统一区块名称
  2. 统一块大小
  3. 统一块索引
  4. 制服区所有制服的名称

我的主要问题是最后一个。例如,这是我的统一块:

uniform MatBlock{
    vec4 MatColor;
    int MatRoughness;
} material;
Run Code Online (Sandbox Code Playgroud)

我希望能够获得制服名称的映射,因此{"MatColor":0, "MatRoughness":16},第二个值是制服的偏移量。这样可以轻松获取和设置偏移量。我的目标是能够做类似的事情uniformbuffer->PushData(0.3f, sizeof(float), "MaterialBlock", "MatRoughness");,所以这会将 UBO 中的 MatRoughness 设置为 0.3。我已经有了获取列表中前 3 项的代码(代码位于下面),但我不知道如何获取名称。

glGetProgramiv(shader, GL_ACTIVE_UNIFORM_BLOCKS, &numblocks);        
for(unsigned int i = 0; i < numblocks; i++){
    // Get the name of the uniform block
    int namelen;
    glGetActiveUniformBlockiv(shader, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &namelen); 
    char blockname[namelen];
    glGetActiveUniformBlockName(shader, i, namelen, NULL, blockname);
                 
    // Add Block Binding
    unsigned int index = glGetUniformBlockIndex(shader, blockname);
    glUniformBlockBinding(shader, index, i);

    // Get the size of the block
    int size;
    glGetActiveUniformBlockiv(shader, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
}
Run Code Online (Sandbox Code Playgroud)

一旦我得到统一的块制服,我将如何使用设置数据glMapData?我有为此编写的伪代码作为示例:

void UniformBuffer::PushData(void* data, unsigned int size, std::string uniformname){
    glBindBuffer(GL_UNIFORM_BUFFER, pm_uboid);
    void* blockptr = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
    mcmcpy(blockptr + pm_uniforms[uniname], data, size);
    glUnmapBuffer(GL_UNIFORM_BUFFER);
}
Run Code Online (Sandbox Code Playgroud)

我不完全确定这是如何工作的,因为很难找到可靠的例子。

总之:

如何获取制服块中所有制服的名称以及如何通过命令更新制服块中的数据glMapBuffer

Nic*_*las 6

\n

我的目标是能够做类似的事情uniformbuffer->PushData(0.3f, sizeof(float), "MaterialBlock", "MatRoughness");

\n
\n

这不是一个值得拥有的目标。有几个原因。

\n

从最一般的意义上来说,UBO 不应视为常规统一值。它们是数据结构,可以直接映射到 C 或 C++ 对象。假设您正在使用std140std430布局(实际上,没有理由使用这些布局),您可以编写一个等效的结构,其字段与 GLSL 中的字段完全映射。

\n

因此,不应该逐个值地更新 UBO。应该通过上传与 UBO 匹配的结构来完成。如果结构很小,则尤其如此。您永远不必查询布局;您应该上传一个适当设计的结构。

\n

此外,UBO 存储在缓冲区对象中。因此,修改它们必须小心,特别是当您对多个对象使用相同的缓冲区时。嗯,这并不需要小心翼翼地完成;你可以随心所欲地做。

\n

只要你不关心性能。

\n

例如,映射缓冲区以在每个值级别上修改它只会降低性能。映射缓冲区会带来巨大的性能成本,因此他们添加了更新的功能,以允许人们映射一次并且永远不会取消映射。不过一旦你这样做了,所有的同步都由你来承担。

\n

具体如何处理这个问题取决于您实际使用它的目的。但这种 API 几乎没有用例。或者至少,没有更好的方法来做到这一点的用例。

\n

至于 API 本身,它根本没有意义。我不知道该uniformBuffer对象应该是什么,但如果它是为了封装着色器中定义的统一块,则该块的名称(“MaterialBlock”)是无关紧要的。重要的是街区的布局。

\n

另外,就块名称而言,它应该存储在 中uniformBuffer,而不是由用户指定。也就是说,这个uniformBuffer 对象应该代表一个特定的统一块。

\n
\n

话虽这么说,如果您绝对必须查询有关 UBO 的布局信息(让我再次强调,您不应该这样做),可以按如下方式完成。

\n

程序中使用的所有(活动)统一块都可以通过内省 API进行查询。对于此示例,我将使用更新的、统一的内省 API

\n

统一块是一个接口,特别命名为GL_UNIFORM_BLOCK。该接口包含一个统一块条目数组,编号为 0 到程序中活动统一块的数量。所以你需要查询这个数字是多少:

\n
GLint numUniformBlocks = 0;\nglGetProgramInterfaceiv(program\xe2\x80\x8b, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES\xe2\x80\x8b, &numUniformBlocks);\n
Run Code Online (Sandbox Code Playgroud)\n

因此,我们只需从 0 循环到numUniformBlocks,循环遍历所有活动的统一块。对于特定的制服块索引,您可以查询其名称、其中有多少制服以及这些制服的列表。该列表将是GL_UNIFORM该程序使用的所有 s 的单个数组的索引。

\n
std::array<GLenum, 3> blockProperties{GL_NAME_LENGTH, GL_NUM_ACTIVE_VARIABLES, GL_BUFFER_DATA_SIZE};\nstd::array<GLint, 3> blockData{};\n\nfor(int blockIx = 0; blockIx < numUniformBlocks; ++blockIx)\n{\n  glGetProgramResourceiv(program, GL_UNIFORM_BLOCK, blockIx, blockProperties.size(), blockProperties.data(), blockData.size(), nullptr, blockData.data());\n\n  //Retrieve name\n  std::string blockName(blockData[0]);\n  glGetProgramResourceName(program\xe2\x80\x8b, GL_UNIFORM_BLOCK, blockIx, blockName.size() + 1, nullptr, blockName\xe2\x80\x8b.data());\n\n  //Retrieve indices of uniforms that are a member of this block.\n  std::vector<GLint> uniformIxs(blockData[1]);\n  GLenum member = GL_ACTIVE_VARIABLES;\n\n  glGetProgramResourceiv(program, GL_UNIFORM_BLOCK, blockIx, 1, &member, uniformIxs.size(), nullptr, uniformIxs.data());\n\n  //We already retrieved the size.\n  auto bufferDataSize = blockData[2];\n}\n
Run Code Online (Sandbox Code Playgroud)\n

检索了统一索引数组后,我们现在可以查询这些统一的属性,例如它们的名称。因此,在上面的循环中,我们只需循环统一索引数组,从接口查询GL_UNIFORM

\n
for(auto unifIx: uniformIxs)\n{\n  GLint nameLength = 0;\n  GLenum nameProp = GL_NAME_LENGTH;\n  glGetProgramResourceiv(program, GL_UNIFORM, unifIx, 1, &nameProp, 1, nullptr, &nameLength);\n\n  std::string unifName(nameLength);\n  glGetProgramResourceName(program\xe2\x80\x8b, GL_UNIFORM, unifIx, unifName.size() + 1, nullptr, unifName.data());\n}\n
Run Code Online (Sandbox Code Playgroud)\n

存储这些数据的位置取决于您。

\n