从零开始shader系列,做个火焰形状的人物描边

mark~~

马住~~~

帮忙解释一下image 这里的0.97 和0.015,怎么来的
假定缩放倍数为k,如果需要中心对齐的话那么
new_uv = uv * (1/k) + (k-1)/2k

mark 住

preview
好棒的火舞(不是,火焰效果),学习一下火焰描边,不过我描边没有用放大+填色+叠加的方案,这个方案有点问题,因为所有的点都在从中心点往外扩的,那些角度大于180°的边就会出现问题。选择另一种描边方案,是对图片取样8次,分别往8个不同的方向偏移取样,获取到描边颜色后,思路和楼主一样的,不过没有用噪声图片取而代之用代码实现的噪声纹理采样,最后效果如图 :smiley:

还是不太明白,辛苦大佬再解释下呢?

根据引擎版本有关系吗?复制effec你的代码拿来用,完全是买家秀和卖家秀

2.4.6

你的头像引起了我的注意,可否借一步说话~

怎么推导的我忘了… 反正大概意思 是先缩放,再平移 保证缩放、平移前后 中心点对齐

试了下 这个方案,效果也有 ,但是如果源图像是plist中的一帧 结果就不对了(感觉采样重复了 好像) 不知道大佬有没有plist中图片的解决方案

plist中的uv不是从0~1的 你在计算的时候需要先把uv坐标还原到0~1然后在纹理采样的时候将uv坐标还原到图集里面的范围区间内去

需要么?我采样周围的时候是用的plist大图的uv, 但是,offset也是用的大图尺寸 ,那么1像素代表的uv不是准的么?另外看我的效果 在编辑器里预览正常 模拟器或者web看的时候就不对了。。。image

你可以打印一下spf身上的uv字段 合图里面的uv不是从0-1开始的 需要自己把真实的uv边界传进去 然后你自己clamp裁剪一下 不然会取样到附近图片的纹理的

好的 谢谢大佬 我试试

    updateWorldVerts(sprite) {
        let local = this._local;
        let verts = this._renderData.vDatas[0];

        let matrix = sprite.node._worldMatrix;
        let matrixm = matrix.m,
            a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
            tx = matrixm[12], ty = matrixm[13];

        let vl = local[0], vr = local[2],
            vb = local[1], vt = local[3];

        let floatsPerVert = this.floatsPerVert;
        let vertexOffset = 0;
        if (CC_NATIVERENDERER) {
            verts[vertexOffset] = vl;
            verts[vertexOffset + 1] = vb;
            vertexOffset += floatsPerVert;
            // right bottom
            verts[vertexOffset] = vr;
            verts[vertexOffset + 1] = vb;
            vertexOffset += floatsPerVert;
            // left top
            verts[vertexOffset] = vl;
            verts[vertexOffset + 1] = vt;
            vertexOffset += floatsPerVert;
            // right top
            verts[vertexOffset] = vr;
            verts[vertexOffset + 1] = vt;
        } else {

            let justTranslate = a === 1 && b === 0 && c === 0 && d === 1;

            if (justTranslate) {
                // left bottom
                verts[vertexOffset] = vl + tx;
                verts[vertexOffset + 1] = vb + ty;
                vertexOffset += floatsPerVert;
                // right bottom
                verts[vertexOffset] = vr + tx;
                verts[vertexOffset + 1] = vb + ty;
                vertexOffset += floatsPerVert;
                // left top
                verts[vertexOffset] = vl + tx;
                verts[vertexOffset + 1] = vt + ty;
                vertexOffset += floatsPerVert;
                // right top
                verts[vertexOffset] = vr + tx;
                verts[vertexOffset + 1] = vt + ty;
            } else {
                let al = a * vl, ar = a * vr,
                    bl = b * vl, br = b * vr,
                    cb = c * vb, ct = c * vt,
                    db = d * vb, dt = d * vt;

                // left bottom
                verts[vertexOffset] = al + cb + tx;
                verts[vertexOffset + 1] = bl + db + ty;
                vertexOffset += floatsPerVert;
                // right bottom
                verts[vertexOffset] = ar + cb + tx;
                verts[vertexOffset + 1] = br + db + ty;
                vertexOffset += floatsPerVert;
                // left top
                verts[vertexOffset] = al + ct + tx;
                verts[vertexOffset + 1] = bl + dt + ty;
                vertexOffset += floatsPerVert;
                // right top
                verts[vertexOffset] = ar + ct + tx;
                verts[vertexOffset + 1] = br + dt + ty;
            }
        }
        
        vertexOffset = 0;
        let min = cc.v2(verts[0],verts[0 + 1]);
        let max = cc.v2(verts[floatsPerVert * 3],verts[floatsPerVert * 3 + 1]);
        let off = cc.v2(max.x - min.x, max.y - min.y);
        // cc.log('Simple updateWorldVerts',sprite.node.name,verts,min.x +','+min.y +'-'+max.x +','+max.y);
        
        // 2(2x32): uv offset // 1(4x8=32): color offset
        // ATTR_POSITION 0-1(2xfloat32) 
        // ATTR_UV0 2-3(2xfloat32)
        // ATTR_COLOR 4(4xint8=32)
        // a_frameInfo 5-8 (4xfloat32)

        let texx = sprite.node.width * sprite.node.scaleX;
        let texy = sprite.node.height * sprite.node.scaleY;
        vertexOffset = 0;
        verts[vertexOffset + 5] = texx;
        verts[vertexOffset + 6] = texy;
        verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
        verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
        vertexOffset += floatsPerVert;
        // right bottom
        verts[vertexOffset + 5] = texx;
        verts[vertexOffset + 6] = texy;
        verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
        verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
        vertexOffset += floatsPerVert;
        // left top
        verts[vertexOffset + 5] = texx;
        verts[vertexOffset + 6] = texy;
        verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
        verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
        vertexOffset += floatsPerVert;
        // right top
        verts[vertexOffset + 5] = texx;
        verts[vertexOffset + 6] = texy;
        verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
        verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    }

需要自定义顶点数据,计算好正确uv传给shader,我这里的

        verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
        verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;

就是计算后的uv

给一个完整的

CustomFrameUVSimpleAssembler.ts



// https://forum.cocos.org/t/topic/120337
// https://forum.cocos.org/t/topic/95087
// 自定义Assembler 把frame的相关信息传进shader


//@ts-ignore
let gfx = cc.gfx;
const vfmtCustom = new gfx.VertexFormat([
    { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
    { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
    { name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
    { name: "a_frameInfo", type: gfx.ATTR_TYPE_FLOAT32, num: 4 }, // xy textureSize(width * scale) // zw localUV
]);


export default class CustomFrameUVSimpleAssembler extends cc.Assembler {
    floatsPerVert = 9;

    verticesCount = 4;
    indicesCount = 6;

    uvOffset = 2;
    colorOffset = 4;

    protected _renderData: cc.RenderData = null;
    protected _local: any = null;          // 中间结果。[l,b,r,t]。node对象左下、右上顶点的本地坐标,即相对于锚点的偏移

    init(comp: cc.RenderComponent) {
        super.init(comp);

        // cc.Assembler2D的初始化放在constructor里
        // 此处把初始化放在init里,以便成员变量能够有机会修改
        this._renderData = new cc.RenderData();
        this._renderData.init(this);

        this.initLocal();
        this.initData();
    }
    // todo: mixin this part
    initData() {
        let data = this._renderData;
        // createFlexData支持创建指定格式的renderData
        data.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt());

        // createFlexData不会填充顶点索引信息,手动补充一下
        let indices = data.iDatas[0];
        let count = indices.length / 6;
        for (let i = 0, idx = 0; i < count; i++) {
            let vertextID = i * 4;
            indices[idx++] = vertextID;
            indices[idx++] = vertextID + 1;
            indices[idx++] = vertextID + 2;
            indices[idx++] = vertextID + 1;
            indices[idx++] = vertextID + 3;
            indices[idx++] = vertextID + 2;
        }
    }

    initLocal() {
        this._local = [];
        this._local.length = 4;
    }
    get verticesFloats() {
        return this.verticesCount * this.floatsPerVert;
    }

    getVfmt() {
        return vfmtCustom;
    }

    getBuffer() {
        //@ts-ignore
        return cc.renderer._handle.getBuffer("mesh", this.getVfmt());
    }


    updateColor(comp, color) {
        // render data = verts = x|y|u|v|color|x|y|u|v|color|...
        // 填充render data中4个顶点的color部分
        let uintVerts = this._renderData.uintVDatas[0];
        if (!uintVerts) return;
        color = color != null ? color : comp.node.color._val;
        let floatsPerVert = this.floatsPerVert;
        let colorOffset = this.colorOffset;
        for (let i = colorOffset, l = uintVerts.length; i < l; i += floatsPerVert) {
            uintVerts[i] = color;
        }
    }

    updateRenderData(sprite) {
        this.packToDynamicAtlas(sprite, sprite._spriteFrame);

        if (sprite._vertsDirty) {
            this.updateUVs(sprite);
            this.updateVerts(sprite);
            sprite._vertsDirty = false;
        }
    }


    updateVerts(sprite) {
        let node = sprite.node,
            cw = node.width, ch = node.height,
            appx = node.anchorX * cw, appy = node.anchorY * ch,
            l, b, r, t;
        if (sprite.trim) {
            l = -appx;
            b = -appy;
            r = cw - appx;
            t = ch - appy;
        }
        else {
            let frame = sprite.spriteFrame,
                ow = frame._originalSize.width, oh = frame._originalSize.height,
                rw = frame._rect.width, rh = frame._rect.height,
                offset = frame._offset,
                scaleX = cw / ow, scaleY = ch / oh;
            let trimLeft = offset.x + (ow - rw) / 2;
            let trimRight = offset.x - (ow - rw) / 2;
            let trimBottom = offset.y + (oh - rh) / 2;
            let trimTop = offset.y - (oh - rh) / 2;
            l = trimLeft * scaleX - appx;
            b = trimBottom * scaleY - appy;
            r = cw + trimRight * scaleX - appx;
            t = ch + trimTop * scaleY - appy;
        }

        let local = this._local;
        local[0] = l;
        local[1] = b;
        local[2] = r;
        local[3] = t;
        this.updateWorldVerts(sprite);
    }

    updateUVs(sprite) {
        let uv = sprite._spriteFrame.uv;
        // this.logOnce(sprite._spriteFrame.uv)
        let uvOffset = this.uvOffset;
        let floatsPerVert = this.floatsPerVert;

        let verts = this._renderData.vDatas[0];

        for (let i = 0; i < 4; i++) {
            let srcOffset = i * 2;
            let dstOffset = floatsPerVert * i + uvOffset;
            verts[dstOffset] = uv[srcOffset];
            verts[dstOffset + 1] = uv[srcOffset + 1];
        }

    }

    
    updateWorldVerts(sprite) {
        let local = this._local;
        let verts = this._renderData.vDatas[0];

        let matrix = sprite.node._worldMatrix;
        let matrixm = matrix.m,
            a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
            tx = matrixm[12], ty = matrixm[13];

        let vl = local[0], vr = local[2],
            vb = local[1], vt = local[3];

        let floatsPerVert = this.floatsPerVert;
        let vertexOffset = 0;
        if (CC_NATIVERENDERER) {
            verts[vertexOffset] = vl;
            verts[vertexOffset + 1] = vb;
            vertexOffset += floatsPerVert;
            // right bottom
            verts[vertexOffset] = vr;
            verts[vertexOffset + 1] = vb;
            vertexOffset += floatsPerVert;
            // left top
            verts[vertexOffset] = vl;
            verts[vertexOffset + 1] = vt;
            vertexOffset += floatsPerVert;
            // right top
            verts[vertexOffset] = vr;
            verts[vertexOffset + 1] = vt;
        } else {

            let justTranslate = a === 1 && b === 0 && c === 0 && d === 1;

            if (justTranslate) {
                // left bottom
                verts[vertexOffset] = vl + tx;
                verts[vertexOffset + 1] = vb + ty;
                vertexOffset += floatsPerVert;
                // right bottom
                verts[vertexOffset] = vr + tx;
                verts[vertexOffset + 1] = vb + ty;
                vertexOffset += floatsPerVert;
                // left top
                verts[vertexOffset] = vl + tx;
                verts[vertexOffset + 1] = vt + ty;
                vertexOffset += floatsPerVert;
                // right top
                verts[vertexOffset] = vr + tx;
                verts[vertexOffset + 1] = vt + ty;
            } else {
                let al = a * vl, ar = a * vr,
                    bl = b * vl, br = b * vr,
                    cb = c * vb, ct = c * vt,
                    db = d * vb, dt = d * vt;

                // left bottom
                verts[vertexOffset] = al + cb + tx;
                verts[vertexOffset + 1] = bl + db + ty;
                vertexOffset += floatsPerVert;
                // right bottom
                verts[vertexOffset] = ar + cb + tx;
                verts[vertexOffset + 1] = br + db + ty;
                vertexOffset += floatsPerVert;
                // left top
                verts[vertexOffset] = al + ct + tx;
                verts[vertexOffset + 1] = bl + dt + ty;
                vertexOffset += floatsPerVert;
                // right top
                verts[vertexOffset] = ar + ct + tx;
                verts[vertexOffset + 1] = br + dt + ty;
            }
        }
        
        vertexOffset = 0;
        let min = cc.v2(verts[0],verts[0 + 1]);
        let max = cc.v2(verts[floatsPerVert * 3],verts[floatsPerVert * 3 + 1]);
        let off = cc.v2(max.x - min.x, max.y - min.y);
        // cc.log('Simple updateWorldVerts',sprite.node.name,verts,min.x +','+min.y +'-'+max.x +','+max.y);
        
        // 2(2x32): uv offset // 1(4x8=32): color offset
        // ATTR_POSITION 0-1(2xfloat32) 
        // ATTR_UV0 2-3(2xfloat32)
        // ATTR_COLOR 4(4xint8=32)
        // a_frameInfo 5-8 (4xfloat32)

        let texx = sprite.node.width * sprite.node.scaleX;
        let texy = sprite.node.height * sprite.node.scaleY;
        vertexOffset = 0;
        verts[vertexOffset + 5] = texx;
        verts[vertexOffset + 6] = texy;
        verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
        verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
        vertexOffset += floatsPerVert;
        // right bottom
        verts[vertexOffset + 5] = texx;
        verts[vertexOffset + 6] = texy;
        verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
        verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
        vertexOffset += floatsPerVert;
        // left top
        verts[vertexOffset + 5] = texx;
        verts[vertexOffset + 6] = texy;
        verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
        verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
        vertexOffset += floatsPerVert;
        // right top
        verts[vertexOffset + 5] = texx;
        verts[vertexOffset + 6] = texy;
        verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
        verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    }

    // updateWorldVerts(comp) {
    //     if (CC_NATIVERENDERER) {
    //         this.updateWorldVertsNative(comp);
    //     } else {
    //         this.updateWorldVertsWebGL(comp);
    //     }
    // }
    // updateWorldVertsNative(sprite) {
    //     let local = this._local;
    //     let verts = this._renderData.vDatas[0];
    //     let floatsPerVert = this.floatsPerVert;
      
    //     let vl = local[0],
    //         vr = local[2],
    //         vb = local[1],
    //         vt = local[3];
      
    //     let vertexOffset: number = 0;
    //     // left bottom
    //     verts[vertexOffset] = vl;
    //     verts[vertexOffset+1] = vb;
    //     vertexOffset += floatsPerVert;
    //     // right bottom
    //     verts[vertexOffset] = vr;
    //     verts[vertexOffset+1] = vb;
    //     vertexOffset += floatsPerVert;
    //     // left top
    //     verts[vertexOffset] = vl;
    //     verts[vertexOffset+1] = vt;
    //     vertexOffset += floatsPerVert;
    //     // right top
    //     verts[vertexOffset] = vr;
    //     verts[vertexOffset+1] = vt;

        
    //     vertexOffset = 0;
    //     let min = cc.v2(verts[0],verts[0 + 1]);
    //     let max = cc.v2(verts[floatsPerVert * 3],verts[floatsPerVert * 3 + 1]);
    //     let off = cc.v2(max.x - min.x, max.y - min.y);
    //     cc.log('Simple updateWorldVerts',sprite.node.name,verts,min.x +','+min.y +'-'+max.x +','+max.y);
        
    //     // 2(2x32): uv offset // 1(4x8=32): color offset
    //     // ATTR_POSITION 0-1(2xfloat32) 
    //     // ATTR_UV0 2-3(2xfloat32)
    //     // ATTR_COLOR 4(4xint8=32)
    //     // a_frameInfo 5-8 (4xfloat32)

    //     let texx = sprite.node.width * sprite.node.scaleX;
    //     let texy = sprite.node.height * sprite.node.scaleY;
    //     vertexOffset = 0;
    //     verts[vertexOffset + 5] = texx;
    //     verts[vertexOffset + 6] = texy;
    //     verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
    //     verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    //     vertexOffset += floatsPerVert;
    //     // right bottom
    //     verts[vertexOffset + 5] = texx;
    //     verts[vertexOffset + 6] = texy;
    //     verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
    //     verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    //     vertexOffset += floatsPerVert;
    //     // left top
    //     verts[vertexOffset + 5] = texx;
    //     verts[vertexOffset + 6] = texy;
    //     verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
    //     verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    //     vertexOffset += floatsPerVert;
    //     // right top
    //     verts[vertexOffset + 5] = texx;
    //     verts[vertexOffset + 6] = texy;
    //     verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
    //     verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    // }
    // updateWorldVertsWebGL(sprite) {
    //     let local = this._local;
    //     let verts = this._renderData.vDatas[0];

    //     let matrix = sprite.node._worldMatrix;
    //     let matrixm = matrix.m,
    //         a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
    //         tx = matrixm[12], ty = matrixm[13];

    //     let vl = local[0], vr = local[2],
    //         vb = local[1], vt = local[3];

    //     let floatsPerVert = this.floatsPerVert;
    //     let vertexOffset = 0;
    //     let justTranslate = a === 1 && b === 0 && c === 0 && d === 1;

    //     if (justTranslate) {
    //         // left bottom
    //         verts[vertexOffset] = vl + tx;
    //         verts[vertexOffset + 1] = vb + ty;
    //         vertexOffset += floatsPerVert;
    //         // right bottom
    //         verts[vertexOffset] = vr + tx;
    //         verts[vertexOffset + 1] = vb + ty;
    //         vertexOffset += floatsPerVert;
    //         // left top
    //         verts[vertexOffset] = vl + tx;
    //         verts[vertexOffset + 1] = vt + ty;
    //         vertexOffset += floatsPerVert;
    //         // right top
    //         verts[vertexOffset] = vr + tx;
    //         verts[vertexOffset + 1] = vt + ty;
    //     } else {
    //         let al = a * vl, ar = a * vr,
    //             bl = b * vl, br = b * vr,
    //             cb = c * vb, ct = c * vt,
    //             db = d * vb, dt = d * vt;

    //         // left bottom
    //         verts[vertexOffset] = al + cb + tx;
    //         verts[vertexOffset + 1] = bl + db + ty;
    //         vertexOffset += floatsPerVert;
    //         // right bottom
    //         verts[vertexOffset] = ar + cb + tx;
    //         verts[vertexOffset + 1] = br + db + ty;
    //         vertexOffset += floatsPerVert;
    //         // left top
    //         verts[vertexOffset] = al + ct + tx;
    //         verts[vertexOffset + 1] = bl + dt + ty;
    //         vertexOffset += floatsPerVert;
    //         // right top
    //         verts[vertexOffset] = ar + ct + tx;
    //         verts[vertexOffset + 1] = br + dt + ty;
    //     }

    //     vertexOffset = 0;
    //     let min = cc.v2(verts[0],verts[0 + 1]);
    //     let max = cc.v2(verts[floatsPerVert * 3],verts[floatsPerVert * 3 + 1]);
    //     let off = cc.v2(max.x - min.x, max.y - min.y);
    //     cc.log('Simple updateWorldVerts',sprite.node.name,verts,min.x +','+min.y +'-'+max.x +','+max.y);
        
    //     // 2(2x32): uv offset // 1(4x8=32): color offset
    //     // ATTR_POSITION 0-1(2xfloat32) 
    //     // ATTR_UV0 2-3(2xfloat32)
    //     // ATTR_COLOR 4(4xint8=32)
    //     // a_frameInfo 5-8 (4xfloat32)

    //     let texx = sprite.node.width * sprite.node.scaleX;
    //     let texy = sprite.node.height * sprite.node.scaleY;
    //     vertexOffset = 0;
    //     verts[vertexOffset + 5] = texx;
    //     verts[vertexOffset + 6] = texy;
    //     verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
    //     verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    //     vertexOffset += floatsPerVert;
    //     // right bottom
    //     verts[vertexOffset + 5] = texx;
    //     verts[vertexOffset + 6] = texy;
    //     verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
    //     verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    //     vertexOffset += floatsPerVert;
    //     // left top
    //     verts[vertexOffset + 5] = texx;
    //     verts[vertexOffset + 6] = texy;
    //     verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
    //     verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    //     vertexOffset += floatsPerVert;
    //     // right top
    //     verts[vertexOffset + 5] = texx;
    //     verts[vertexOffset + 6] = texy;
    //     verts[vertexOffset + 7] = (verts[vertexOffset] - min.x) / off.x;
    //     verts[vertexOffset + 8] = 1 - (verts[vertexOffset + 1] - min.y) / off.y;
    // }


    fillBuffers(comp, renderer) {
        if (renderer.worldMatDirty) {
            this.updateWorldVerts(comp);
        }

        let renderData = this._renderData;
        let vData = renderData.vDatas[0];
        let iData = renderData.iDatas[0];

        // @ts-ignore
        let buffer = this.getBuffer(renderer);
        let offsetInfo = buffer.request(this.verticesCount, this.indicesCount);

        // buffer data may be realloc, need get reference after request.

        // fill vertices
        let vertexOffset = offsetInfo.byteOffset >> 2,
            vbuf = buffer._vData;

        if (vData.length + vertexOffset > vbuf.length) {
            vbuf.set(vData.subarray(0, vbuf.length - vertexOffset), vertexOffset);
        } else {
            vbuf.set(vData, vertexOffset);
        }

        // fill indices
        let ibuf = buffer._iData,
            indiceOffset = offsetInfo.indiceOffset,
            vertexId = offsetInfo.vertexOffset;
        for (let i = 0, l = iData.length; i < l; i++) {
            ibuf[indiceOffset++] = vertexId + iData[i];
        }
    }

    packToDynamicAtlas(comp, frame) {
        if (CC_TEST) return;

        if (!frame._original && cc.dynamicAtlasManager && frame._texture.packable && frame._texture.loaded) {
            let packedFrame = cc.dynamicAtlasManager.insertSpriteFrame(frame);
            // @ts-ignore
            if (packedFrame) {
                frame._setDynamicAtlasFrame(packedFrame);
            }
        }
        let material = comp._materials[0];
        if (!material) return;

        if (material.getProperty('texture') !== frame._texture._texture) {
            // texture was packed to dynamic atlas, should update uvs
            comp._vertsDirty = true;
            comp._updateMaterial();
        }
    }



}

a_frameInfo.xy 是我自己传入的textureSize我有别的用
a_frameInfo.zw 就是图集中的换算后的uv

SpriteWithFrameUV.ts

@ccclass
export default class AvatarSprite extends cc.Sprite {
    // _resetAssembler() {
    //     this.setVertsDirty();
    //     let assembler = this._assembler = new CustomFrameUVAssembler();
    //     assembler.init(this);
    // }

}

cc.Assembler.register(AvatarSprite,{
    getConstructor(sp) {
        let ctor = CustomFrameUVSimpleAssembler;

        if(sp.type === cc.Sprite.Type.SLICED){
            ctor = CustomFrameUVSlicedAssembler;
        }
        return ctor;
    }
})

1赞

:+1: nice 感谢大佬 ,已经用到我的游戏中了 :laughing:

实现了,但是怎么让火焰横着飘呢?

1赞

大佬,复制你的 CCEffect ,为什么弄出来是这样的静态图? :rofl: image

如果可以的话,把这个整成demo就好了