Cocos Creator:UBO 内存布局策略
推荐:将NSDT场景编辑器加入你的3D工具链
3D工具集:NSDT简石数字孪生
UBO 内存布局策略
Cocos Shader 规定,所有非 sampler 类型的 uniform 都应以 UBO(Uniform Buffer Object/Uniform Block)形式声明。
以内置着色器 builtin-standard.effect
为例,其 uniform block 声明如下:
uniform Constants {
vec4 tilingOffset;
vec4 albedo;
vec4 albedoScaleAndCutoff;
vec4 pbrParams;
vec4 miscParams;
vec4 emissive;
vec4 emissiveScaleParam;
};
并且所有的 UBO 应当遵守以下规则:
- 不应出现 vec3 成员;
- 对数组类型成员,每个元素 size 不能小于 vec4;
- 不允许任何会引入 padding 的成员声明顺序。
Cocos Shader 在编译时会对上述规则进行检查,以便在导入错误(implicit padding 相关)时及时提醒修改。
这可能听起来有些过分严格,但背后有非常务实的考量:
首先,UBO 是渲染管线内要做到高效数据复用的唯一基本单位,离散声明已不是一个选项;
其次,WebGL2 的 UBO 只支持 std140 布局,它遵守一套比较原始的 padding 规则:
所有 vec3 成员都会补齐至 vec4:
uniform ControversialType {
vec3 v3_1; // offset 0, length 16 [IMPLICIT PADDING!]
}; // total of 16 bytes
任意长度小于 vec4 类型的数组和结构体,都会将元素补齐至 vec4:
uniform ProblematicArrays {
float f4_1[4]; // offset 0, stride 16, length 64 [IMPLICIT PADDING!]
}; // total of 64 bytes
所有成员在 UBO 内的实际偏移都会按自身所占字节数对齐:
uniform IncorrectUBOOrder {
float f1_1; // offset 0, length 4 (aligned to 4 bytes)
vec2 v2; // offset 8, length 8 (aligned to 8 bytes) [IMPLICIT PADDING!]
float f1_2; // offset 16, length 4 (aligned to 4 bytes)
}; // total of 32 bytes
uniform CorrectUBOOrder {
float f1_1; // offset 0, length 4 (aligned to 4 bytes)
float f1_2; // offset 4, length 4 (aligned to 4 bytes)
vec2 v2; // offset 8, length 8 (aligned to 8 bytes)
}; // total of 16 bytes
这意味着大量的空间浪费,且某些设备的驱动实现也并不完全符合此标准,因此目前 Cocos Shader 选择限制这部分功能的使用,以帮助排除一部分非常隐晦的运行时问题。
由3D建模学习工作室 翻译整理,转载请注明出处!