#18949·cocos-engine

3.8.7 UIRender组装数据接口postUpdateAssembler问题

Author: linyngflyCreated Aug 27, 2025Updated Aug 24, 2026
LabelsBugNeeds Triage

Cocos Creator version

3.8.7

System information

MacOS google 浏览器

Issue description

项目中很多自定义组件使用了UIRender postUpdateAssembler 方法,进行顶点uv、颜色、坐标的定义,3.8.6 版本各组件功能正常,升级到3.8.7后,postUpdateAssembler 引擎不再触发调用,看了引擎源码修改,和 batcher-2d.ts加入到新功能Sorting2d有一定关系,尝试引擎定扩展定制修改,会有其他渲染问题,目前项目升级卡在这个问题上,麻烦帮忙看一下,有什么解决方案

Relevant error log output

Steps to reproduce

Minimal reproduction project

enum ColorMode { /** * 双颜色 / Double = 0, /* * 左上、右上、左下、右下四颜色 */ Four = 1, }

@ccclass('CCGradientRender') @executeInEditMode @requireComponent(UIRenderer) @menu('weg/render/CCGradientRender(颜色渐变渲染器,支持Label、Sprite等继承于UIRenderer的对象)') export class CCGradientRender extends Component { @property private _colorMode: ColorMode = ColorMode.Double; @property({ type: Enum(ColorMode), tooltip: DEV && '颜色模式,双颜色 | 四颜色', }) private get colorMode() { return this._colorMode; } private set colorMode(value: ColorMode) { this._colorMode = value; this.updateColor(); }

@property
private _colorT: Color = new Color(255, 255, 255, 255);
@property({
    displayName: DEV && '⬆ 顶部颜色',
    visible: function () {
        return this.colorMode == ColorMode.Double;
    },
})
private get colorT() {
    return this._colorT;
}
private set colorT(value: Color) {
    this._colorT = value;
    this.updateColor();
}

@property
private _colorB: Color = new Color(255, 255, 255, 255);
@property({
    displayName: DEV && '⬇ 底部颜色',
    visible: function () {
        return this.colorMode == ColorMode.Double;
    },
})
private get colorB() {
    return this._colorB;
}
private set colorB(value: Color) {
    this._colorB = value;
    this.updateColor();
}

@property
private _colorLT: Color = new Color(255, 255, 255, 255);
@property({
    displayName: DEV && '↖ 左上',
    visible: function () {
        return this.colorMode == ColorMode.Four;
    },
})
private get colorLT() {
    return this._colorLT;
}
private set colorLT(value: Color) {
    this._colorLT = value;
    this.updateColor();
}
@property
private _colorRT: Color = new Color(255, 255, 255, 255);
@property({
    displayName: DEV && '↗ 右上',
    visible: function () {
        return this.colorMode == ColorMode.Four;
    },
})
private get colorRT() {
    return this._colorRT;
}
private set colorRT(value: Color) {
    this._colorRT = value;
    this.updateColor();
}

@property
private _colorLB: Color = new Color(255, 255, 255, 255);
@property({
    displayName: DEV && '↙ 左下',
    visible: function () {
        return this.colorMode == ColorMode.Four;
    },
})
private get colorLB() {
    return this._colorLB;
}
private set colorLB(value: Color) {
    this._colorLB = value;
    this.updateColor();
}
@property
private _colorRB: Color = new Color(255, 255, 255, 255);
@property({
    displayName: DEV && '↘ 右下',
    visible: function () {
        return this.colorMode == ColorMode.Four;
    },
})
private get colorRB() {
    return this._colorRB;
}
private set colorRB(value: Color) {
    this._colorRB = value;
    this.updateColor();
}

private ur: UIRenderer = null;
protected onLoad() {
    this.ur = this.node.getComponent(UIRenderer);
    if (!(this.ur instanceof Sprite || this.ur instanceof Label)) {
        weg.warn('CCGradientRender onLoad, Label or Sprite only');
        this.destroy();
        return;
    }
}

protected onEnable() {
    // 启用顶点透明度(否则透明度只受color.a影响)
    this.ur['_useVertexOpacity'] = true;
    const postUpdateAssembler = this.ur.postUpdateAssembler;
    this.ur.postUpdateAssembler = () => {
        this.updateColor();
        postUpdateAssembler.apply(this.ur);
    };
}

protected onDisable() {
    if (!this.ur['_renderData']) {
        return;
    }
    const renderData = this.ur['_renderData'];
    let vb = renderData.chunk.vb;
    let color = this.ur.color;

    // 动态计算顶点布局,适配CCGray等组件修改的顶点格式
    const stride = renderData.floatStride || 9; // 默认9个float,CCGray会变为14个
    const colorOffset = stride === 14 ? 9 : 5; // CCGray时写入a_gray_color(偏移9),否则写入ATTR_COLOR(偏移5)

    // 消除渐变效果,恢复原始颜色
    const colorR = color.r / 255;
    const colorG = color.g / 255;
    const colorB = color.b / 255;
    const colorA = color.a / 255;

    // 所有顶点设置统一颜色
    let offset = colorOffset;
    for (let i = 0; i < renderData['_vc']; i++) {
        vb[offset] = colorR;
        vb[offset + 1] = colorG;
        vb[offset + 2] = colorB;
        vb[offset + 3] = colorA;
        offset += stride;
    }
}

private updateColor() {
    if (!this.ur || !this.ur['_renderData']) {
        return;
    }

    const renderData = this.ur['_renderData'];
    let vb = renderData.chunk.vb;
    // 获取UIRenderer的原始颜色用于透明度混合
    let baseColor = this.ur.color;
    let baseA = baseColor.a / 255;

    // 动态计算顶点布局,适配CCGray等组件修改的顶点格式
    // 默认9个float,CCGray会变为14个
    const stride = renderData.floatStride || 9;
    // CCGray时写入a_gray_color(偏移9),否则写入ATTR_COLOR(偏移5)
    let offset = stride === 14 ? 9 : 5;

    // _isGray 为 true 时的变暗因子
    const darkenFactor = this.ur['_isGray'] ? 0.5 : 1.0;
    if (this._colorMode === ColorMode.Double) {
        // 双颜色模式:上下渐变
        const vbColors = [this._colorB, this._colorB, this._colorT, this._colorT];

        // 按照 左下、右下、左上、右上的顺序写入颜色
        for (let i = 0, len = vbColors.length; i < len; i++) {
            let color = vbColors[i];
            vb[offset] = (color.r / 255) * darkenFactor;
            vb[offset + 1] = (color.g / 255) * darkenFactor;
            vb[offset + 2] = (color.b / 255) * darkenFactor;
            vb[offset + 3] = (color.a / 255) * baseA;
            offset += stride;
        }
    } else {
        // 四颜色模式:四个角独立颜色
        const vbColors = [this._colorLB, this._colorRB, this._colorLT, this._colorRT];
        for (let i = 0, len = vbColors.length; i < len; i++) {
            let color = vbColors[i];
            vb[offset] = (color.r / 255) * darkenFactor;
            vb[offset + 1] = (color.g / 255) * darkenFactor;
            vb[offset + 2] = (color.b / 255) * darkenFactor;
            vb[offset + 3] = (color.a / 255) * baseA;
            offset += stride;
        }
    }
}

}