使用统一缓冲区对象进行批处理渲染

Batched rendering with Uniform Buffer Object

本文关键字:批处理 对象 缓冲区      更新时间:2023-10-16

我正在更改我的基本渲染器,使其成为批处理渲染器以提高性能。我已经成功地更改了顶点数据以在单个批次中绘制所有网格,但是当我想处理多个材质时,就会出现问题。

显然,我不能使用普通uniforms,因为我要批处理大量网格,因此我想使用统一缓冲区对象来存储所有材质数据。

问题是,如何更新此缓冲区?

如果我像这样设置我的 UBO:

layout(std140) uniform MATERIAL
{
    vec4 Color[20];
    float Specular[20];
    float Roughness[20];
    float Metallic[20];
    float ReflectionIntensity[20];
};

我不认为那么,当我提交单个材料的数据时,我可以使用基于材料指数计算的起始偏移量并提交这样的数据:

struct Material {
    float color[4];
    float specular;
    float roughness;
    float metallic;
    float reflectionIntensity;
};
int bufferStride = 32; // 16 (vec4) + 4 (float) + 4 (float) + 4 (float) + 4 (float)
int offset = bufferStride * updatingMaterialIndex;
Material m;
m.color...
glBufferSubData(GL_UNIFORM_BUFFER, offset, &m, sizeof(Material));

因为我认为 OpenGL 的内存中将有 20 vec4后跟 80 float

那我该怎么做呢?我必须单独计算每个元素的偏移量吗?

另外,我应该如何索引网格使用的材质?我应该将材质索引作为顶点属性传递吗?

您最初的建议是使用包含数组的结构。那么为什么不做相反的事情:一个包含结构的数组呢?

struct Material
{
    vec4 Color;
    float Specular;
    float Roughness;
    float Metallic;
    float ReflectionIntensity;
}
layout(std140) uniform Materials
{
    Material mtls[20];
};

然后,您将在 CPU 上构建类似的阵列。

现在要执行此操作,必须确保遵循std140的对齐规则。特别重要的是结构和阵列的对齐。由于Material有一个vec4,因此其基本对齐方式为 16。数组元素之间的步幅必须是数组元素基本对齐方式的倍数。

因此,mtls[20]的大小为 32 * 20 字节。即使您从Material中删除了一个浮点数,它仍然是该大小。

如果您真的想保留数组结构方法,您只需要在 CPU 上使用相应的数据结构。