(四)【源码阅读】CocosCreator3.x 应用在UI(Sprite) 上的 shader(.effect) 的合批,通过自定义顶点参数

源码阅读部分

顶点数量、布局相关设置

针对 UI 所使用的 Mesh 的顶点设置:如 simple 模式使用 1个矩形(2x2个顶点),sliced 模式使用 9个矩形(4x4个顶点)

  1. dataLength 相当于顶点数量。
  2. vertexRow 和 vertexCol 描述了网格形状。
  3. 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

  1. 对于 in vec2 a_texCoord;
  2. 查下述代码得 vec2: Format.RG32F
  3. RenderData.add 时用 new gfx.Attribute(gfx.AttributeName.ATTR_COLOR, gfx.Format.RG32F)

例子2

  1. 对于 in int a_gridIndex;
  2. 查下述代码得 int: Format.R32I
  3. RenderData.add 时用 new gfx.Attribute("a_gridIndex", gfx.Format.R32I)

注意:在实际开发中(ccc版本号3.8.0),发现 vec4 变量(对应 gfx.Format.RGBA32F)在使用中异常。初始化值会被重置。
gfx.Format.RG32Fgfx.Format.RGB32F 经过测试可用。

offline-mappings.ts

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.tsupdateColor 数据为例子。

  1. 通过 renderData.chunk.vb 拿到 顶点数据Buffer。
  2. 根据你所设计(使用)的 顶点数据格式 来确定 字段offset。如这里的 colorOffset = 5
  3. 通过在对应的位置设置你的 字段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.effectsprite-vsa_positiona_texCoorda_color 的写法。
“自定义顶点参数”——所以我们需要在 顶点着色器,sprite-vs 中去获取。
如果要传递到 片元着色器,需要在 sprite-vs 中通过 out 变量传递,如 out vec4 colorout 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;
  }
}%
posted @ 2023-10-26 14:17  bakabird1998  阅读(92)  评论(0编辑  收藏  举报