(四)【源码阅读】CocosCreator3.x 应用在UI(Sprite) 上的 shader(.effect) 的合批,通过自定义顶点参数
源码阅读部分
顶点数量、布局相关设置
针对 UI 所使用的 Mesh 的顶点设置:如 simple 模式使用 1个矩形(2x2个顶点),sliced 模式使用 9个矩形(4x4个顶点)
- dataLength 相当于顶点数量。
- vertexRow 和 vertexCol 描述了网格形状。
- SetIndexBuffer 则描述网格中所有“三角形”分别由哪3个顶点构成的。
simple.ts
createData(sprite: Sprite) {
const renderData = sprite.requestRenderData();
renderData.dataLength = 4;
renderData.resize(4, 6);
renderData.vertexRow = 2;
renderData.vertexCol = 2;
renderData.chunk.setIndexBuffer(QUAD_INDICES);
return renderData;
},
sliced.ts
createData (sprite: Sprite) {
const renderData: RenderData | null = sprite.requestRenderData()!;
// 0-4 for local vertex
renderData.dataLength = 16;
renderData.resize(16, 54);
renderData.vertexRow = 4;
renderData.vertexCol = 4;
this.QUAD_INDICES = new Uint16Array(54);
this.createQuadIndices(4, 4);
renderData.chunk.setIndexBuffer(this.QUAD_INDICES);
return renderData;
},
定义顶点数据格式
ui-renderer.ts
Sprite
继承了 UIRenderer
,所以也有 requestRenderData
。并且没有重写。
/**
* @en Request new render data object.
* @zh 请求新的渲染数据对象。
* @return @en The new render data. @zh 新的渲染数据。
*/
public requestRenderData(drawInfoType = RenderDrawInfoType.COMP) {
const data = RenderData.add();
data.initRenderDrawInfo(this, drawInfoType);
this._renderData = data;
return data;
}
render-data.ts
RenderData.add
默认顶点格式是 vfmtPosUvColor
。所以 Sprite
默认的顶点数据格式就是 vfmtPosUvColor
,即 pos
,uv
,color
。
public static add (vertexFormat = vfmtPosUvColor, accessor?: StaticVBAccessor) {
const rd = new RenderData(vertexFormat, accessor);
if (!accessor) {
const batcher = director.root!.batcher2D;
accessor = batcher.switchBufferAccessor(rd._vertexFormat);
}
rd._accessor = accessor;
return rd;
}
RenderData.add 的参数怎么填
怎么将 effect 中写的 glsl 的变量类型,跟对应的 gfx.Format.XXX 对应上?
例子1
- 对于
in vec2 a_texCoord;
- 查下述代码得
vec2: Format.RG32F
RenderData.add
时用new gfx.Attribute(gfx.AttributeName.ATTR_COLOR, gfx.Format.RG32F)
例子2
- 对于
in int a_gridIndex;
- 查下述代码得
int: Format.R32I
RenderData.add
时用new gfx.Attribute("a_gridIndex", gfx.Format.R32I)
注意:在实际开发中(ccc版本号3.8.0),发现 vec4
变量(对应 gfx.Format.RGBA32F
)在使用中异常。初始化值会被重置。
gfx.Format.RG32F
和 gfx.Format.RGB32F
经过测试可用。
const formatMap = {
bool: Format.R8,
bvec2: Format.RG8,
bvec3: Format.RGB8,
bvec4: Format.RGBA8,
int: Format.R32I,
ivec2: Format.RG32I,
ivec3: Format.RGB32I,
ivec4: Format.RGBA32I,
uint: Format.R32UI,
uvec2: Format.RG32UI,
uvec3: Format.RGB32UI,
uvec4: Format.RGBA32UI,
float: Format.R32F,
vec2: Format.RG32F,
vec3: Format.RGB32F,
vec4: Format.RGBA32F,
int8_t: Format.R8I,
i8vec2: Format.RG8I,
i8vec3: Format.RGB8I,
i8vec4: Format.RGBA8I,
uint8_t: Format.R8UI,
u8vec2: Format.RG8UI,
u8vec3: Format.RGB8UI,
u8vec4: Format.RGBA8UI,
int16_t: Format.R16I,
i16vec2: Format.RG16I,
i16vec3: Format.RGB16I,
i16vec4: Format.RGBA16I,
uint16_t: Format.R16UI,
u16vec2: Format.RG16UI,
u16vec3: Format.RGB16UI,
u16vec4: Format.RGBA16UI,
float16_t: Format.R16F,
f16vec2: Format.RG16F,
f16vec3: Format.RGB16F,
f16vec4: Format.RGBA16F,
// no suitable conversions:
mat2: Format.RGBA32F,
mat3: Format.RGBA32F,
mat4: Format.RGBA32F,
mat2x2: Format.RGBA32F,
mat3x3: Format.RGBA32F,
mat4x4: Format.RGBA32F,
mat2x3: Format.RGBA32F,
mat2x4: Format.RGBA32F,
mat3x2: Format.RGBA32F,
mat3x4: Format.RGBA32F,
mat4x2: Format.RGBA32F,
mat4x3: Format.RGBA32F,
};
顶点数据设置
以simple.ts
的 updateColor
数据为例子。
- 通过
renderData.chunk.vb
拿到 顶点数据Buffer。 - 根据你所设计(使用)的 顶点数据格式 来确定 字段offset。如这里的
colorOffset = 5
。 - 通过在对应的位置设置你的 字段value。
simple.ts
updateColor(sprite: Sprite) {
const renderData = sprite.renderData!;
const vData = renderData.chunk.vb;
let colorOffset = 5;
const color = sprite.color;
const colorR = color.r / 255;
const colorG = color.g / 255;
const colorB = color.b / 255;
const colorA = color.a / 255;
for (let i = 0; i < 4; i++, colorOffset += renderData.floatStride) {
vData[colorOffset] = colorR;
vData[colorOffset + 1] = colorG;
vData[colorOffset + 2] = colorB;
vData[colorOffset + 3] = colorA;
}
},
effect内怎么写
参考内置的 Sprite 默认 shader builtin-sprite.effect
中 sprite-vs
中 a_position
、a_texCoord
、a_color
的写法。
“自定义顶点参数”——所以我们需要在 顶点着色器,sprite-vs
中去获取。
如果要传递到 片元着色器,需要在 sprite-vs
中通过 out
变量传递,如 out vec4 color
和 out vec2 uv0
。
另外由 顶点着色器 传递给 片元着色器 的变量需要注意其值会进行 插值计算。
CCProgram sprite-vs %{
...
in vec3 a_position;
in vec2 a_texCoord;
in vec4 a_color;
out vec4 color;
out vec2 uv0;
vec4 vert () {
vec4 pos = vec4(a_position, 1);
#if USE_LOCAL
pos = cc_matWorld * pos;
#endif
#if USE_PIXEL_ALIGNMENT
pos = cc_matView * pos;
pos.xyz = floor(pos.xyz);
pos = cc_matProj * pos;
#else
pos = cc_matViewProj * pos;
#endif
uv0 = a_texCoord;
#if SAMPLE_FROM_RT
CC_HANDLE_RT_SAMPLE_FLIP(uv0);
#endif
color = a_color;
return pos;
}
}%