统一变量的优化:Uniform Block & UBO - MartinRGB/GLES30_ProgrammingGuide_NDK GitHub Wiki
统一变量块 (Uniform Block) 和 统一变量缓冲区对象 ( Uniform Buffer Object)
使用 UBO 的方式可以建立缓冲区存储统一变量快数据,在统一变量块大幅更新时,降低 API 开销。
循环绘制多块buffer,而每次循环都要给buffer传入大量的uniform,导致shader的渲染效率极低。
除此之外, UBO 可以在多个 program 中共享,只需设置一次而已。而且可以存储更多的 uniform 数据。
一个 UBO 构建的案例如下:
GLuint blockId,bufferId;
GLint blockSize;
GLuint bindingPoint = 1;
GLFloat lightData[] = {
//LightDirection
1.0f,0.0f,0.0f,0.0f,
//LightPosition
0.0f,0.0f,0.0f,1.0f
}
//检索&获取统一变量块 索引 - glGetUniformBlockIndex(program,blockName)
blockId = glGetUniformBlockIndex(program,"LightBlock");
//绑定索引 和 统一变量块绑定点 - glUniformBlockBinding(program,blockIndex,blockBinding)
glUniformBlockBinding(program,blockId,bindingPoint);
//确定 Uniform Block 的细节 - glGetActiveUniformBlockname (program,index,pname,params)
glGetActiveUniformBlockiv(program,blockId,GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
//创建并填充缓冲区对象
glGenBuffers(1,&bufferId);
glBindBuffer(GL_UNIFORM_BUFFER,bufferId);
glBufferData(GL_UNIFORM_BUFFER,blockSize,lightData,GL_DYNAMIC_DRAW);
//将 统一变量快 绑定点 和缓冲区对象绑定
glBindBufferBase(GL_UNIFORM_BUFFER,bindingPoint,buffer);
在 8.2.2 中,构建 UBO:
Shader 中:
//绑定点1
layout (binding = 0) uniform u_material {
vec4 material_ambient_color;
vec4 material_diffuse_color;
vec4 material_specular_color;
float material_specular_exponent;
};
//绑定点2
layout (binding = 1) uniform u_light {
vec3 light_direction;
vec3 light_halfplane;
vec4 light_ambient_color;
vec4 light_diffuse_color;
vec4 light_specular_color;
};
...
在 main.c
中
typedef struct
{
// material uniform block
GLuint materaialBindingPoint;
GLuint materialBuffer;
GLuint materialBlockIndex;
// light uniform block
GLuint lightBindingPoint;
GLuint lightBuffer;
GLuint lightBlockIndex;
} UserData;
GLfloat materialFloats[13] = {
//ambient_color
0.2f, 0.2f, 0.2f, 1.0f,
//diffuse_color
0.7f, 0.7f, 1.0f, 1.0f,
//specular_color
0.5f, 0.5f, 0.5f, 1.0f,
//specular_exponent
64.0f};
GLfloat lightFloats[18] = {
//direction
0.0f, 1.0f, 1.0f,
//halfplane
0.0f, 0.4f, 0.0f,
//ambient_color
1.0f, 1.0f, 1.0f, 1.0f,
//diffuse_color
1.0f, 0.0f, 1.0f, 1.0f,
//specular_color
1.0f, 1.0f, 1.0f, 1.0f
};
int Init ( ESContext *esContext ){
...
// 将Shader中绑定点和 material 和 light 的索引分别绑定
userData->materaialBindingPoint = 0;
userData->materialBlockIndex = glGetUniformBlockIndex(userData -> programObject, "u_material");
glUniformBlockBinding(userData -> programObject, userData -> materialBlockIndex, userData -> materaialBindingPoint);
userData->lightBindingPoint = 1;
userData->lightBlockIndex = glGetUniformBlockIndex(userData -> programObject, "u_light");
glUniformBlockBinding(userData -> programObject, userData -> lightBlockIndex, userData -> lightBindingPoint);
...
}
...
void Draw ( ESContext *esContext ){
// 缓冲区 和 Material 绑定点绑定
glGenBuffers(1, &userData->materialBuffer);
glBindBuffer(GL_UNIFORM_BUFFER, userData->materialBuffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(materialFloats), materialFloats, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, userData->materaialBindingPoint, userData->materialBuffer);
// 缓冲区 和 Light 绑定点绑定
glGenBuffers(1, &userData->lightBuffer);
glBindBuffer(GL_UNIFORM_BUFFER, userData->lightBuffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(lightFloats), lightFloats, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, userData->lightBindingPoint, userData->lightBuffer);
}
更多参考: