统一变量的优化: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);
}


更多参考:

OpenGL缓冲区对象之UBO Uniform Block