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