opengl 获取制服块中制服的名称

k5ifujac  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(150)

所以我问了这个问题:Optimize Uniform Transmission,并建议使用统一缓冲区。我做了一些研究,并试图实现它,但遇到了一个问题,加载格式的统一块从着色器。在我的项目中,我有一个着色器类,加载所有的制服,顶点属性,并将它们存储在着色器中,这样用户就可以轻松地更改这些值,而不必从着色器。我试图做同样的统一块,但我不知道现在如何检索所有的数据,我需要。
这是我尝试从着色器获取的数据类型:
1.统一块名称
1.统一块大小
1.统一块索引
1.制服区所有制服的名字
我的主要问题是最后一个。举个例子,这是我的制服块:

uniform MatBlock{
    vec4 MatColor;
    int MatRoughness;
} material;

我希望能够得到制服名称的Map,因此{"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);
}

一旦我得到了统一的块统一,我将如何使用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);
}

我不完全确定这是如何工作的,因为很难找到可靠的例子。
总而言之:
如何获取制服区中所有制服的名称?如何通过glMapBuffer命令更新制服区中的数据?

ezykj2lf

ezykj2lf1#

我的目标是能够做类似uniformbuffer->PushData(0.3f, sizeof(float), "MaterialBlock", "MatRoughness");的事情,
这不是一个值得拥有的目标,原因有几个。
从最普遍的意义上讲,UBO不应该被当作常规的统一值来对待。它们是数据结构,可以直接Map到C或C++对象。假设你使用的是std140std430布局(实际上,没有理由不使用这些布局),你可以写一个等价的struct,它的字段正好Map到GLSL中的字段。
所以更新UBO不应该在逐值级别上完成。它应该通过上传一个与UBO匹配的结构体来完成。当结构体很小时尤其如此。你不应该查询布局;您应该只上传一个适当设计的结构。
此外,UBO存储在缓冲区对象中。因此,修改它们必须小心,* 特别是 * 如果你对多个对象使用同一个缓冲区。你想怎么做都行。
只要你不在乎性能。
例如,Map缓冲区以在每个值的级别上修改它只是放弃了性能。Map缓冲区具有如此巨大的性能代价,以至于他们添加了更新的功能以允许人们Map它一次并且永远不会取消它。尽管一旦你这样做了,所有的同步都是你的责任。
具体如何处理取决于您实际使用它的目的。但这种API几乎没有用例。或者至少,没有更好的方法来实现它的用例。
至于API本身,它就是没有意义的。我不知道uniformBuffer对象应该是什么,但如果它是用来封装着色器中定义的统一块,那么该块的 name(“MaterialBlock”)是无关紧要的。重要的是该块的 layout
同样,块名也很重要......它应该存储在uniformBuffer中,而不是由用户指定。也就是说,这个uniformBuffer对象应该表示一个特定的统一块。
也就是说,如果您绝对必须查询有关UBO的布局信息(请允许我再次强调,您不应该这样做),可以按如下方式进行。
程序中使用的所有(活动的)统一块都可以通过introspection API进行查询。
统一块是一个名为GL_UNIFORM_BLOCK的接口。这个接口包含一个统一块条目数组,其编号为0到程序中活动的统一块的数目。因此,你需要查询该编号是多少:

GLint numUniformBlocks = 0;
glGetProgramInterfaceiv(program​, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES​, &numUniformBlocks);

所以我们简单地从0到numUniformBlocks循环,循环遍历所有活动的统一块。对于一个特定的统一块索引,你可以查询它的名称,其中有多少个统一,以及这些统一的列表。该列表将成为该程序使用的所有GL_UNIFORM的一个数组的索引。

std::array<GLenum, 3> blockProperties{GL_NAME_LENGTH, GL_NUM_ACTIVE_VARIABLES, GL_BUFFER_DATA_SIZE};
std::array<GLint, 3> blockData{};

for(int blockIx = 0; blockIx < numUniformBlocks; ++blockIx)
{
  glGetProgramResourceiv(program, GL_UNIFORM_BLOCK, blockIx, blockProperties.size(), blockProperties.data(), blockData.size(), nullptr, blockData.data());

  //Retrieve name
  std::string blockName(blockData[0]);
  glGetProgramResourceName(program​, GL_UNIFORM_BLOCK, blockIx, blockName.size() + 1, nullptr, blockName​.data());

  //Retrieve indices of uniforms that are a member of this block.
  std::vector<GLint> uniformIxs(blockData[1]);
  GLenum member = GL_ACTIVE_VARIABLES;

  glGetProgramResourceiv(program, GL_UNIFORM_BLOCK, blockIx, 1, &member, uniformIxs.size(), nullptr, uniformIxs.data());

  //We already retrieved the size.
  auto bufferDataSize = blockData[2];
}

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

for(auto unifIx: uniformIxs)
{
  GLint nameLength = 0;
  GLenum nameProp = GL_NAME_LENGTH;
  glGetProgramResourceiv(program, GL_UNIFORM, unifIx, 1, &nameProp, 1, nullptr, &nameLength);

  std::string unifName(nameLength);
  glGetProgramResourceName(program​, GL_UNIFORM, unifIx, unifName.size() + 1, nullptr, unifName.data());
}

存储这些数据的位置由您决定。

相关问题