加载网络图片制作圆形头像的shader合批处理

image

效果如上。

实现的原理:加载远程图片符合动态合图功能就会合到图集里,spriteframe的uv值也会产生变化,所以需要把合图后的uv值传递到shader中(用颜色值传递),还有图片有可能是长方形,传递宽高比(用坐标z传递) ,从中心位置按照宽高最小的值为圆形直径进行圆形处理。这样就共用同一个材质达到合批效果,降低了drawcall。(官方的动态合图空间利用的不是太好,没塞满就创建新的合图了)

实现的主要代码:

const spriteFrame: SpriteFrame = await 加载网络图片获取spriteframe;

        if (!spriteFrame) return;

        const { width, height } = spriteFrame.original?._texture || spriteFrame.texture;

        console.log(width, height);

        //宽高比

        const value = width / height;

        this.sprite.spriteFrame = spriteFrame;

        //延迟一帧,就能获取动态合图后的spriteFrame的uv值

        await new Promise((resolve) => this.scheduleOnce(resolve, 0));

        console.log(spriteFrame.uv);

        //颜色值传递合批后的新uv

        if (spriteFrame.original) {

            console.log("合图");

            this.sprite.color = color(

                spriteFrame.uv[0] * 255,//uv.x min

                spriteFrame.uv[2] * 255,//uv.x max

                spriteFrame.uv[5] * 255,//uv.y min

                spriteFrame.uv[3] * 255,//uv.y max

            );

        } else {

            console.log("非合图");

            this.sprite.color = color(

                0, 0, 0, 1

            );

        }

        //通过z值传递宽高比

        this.node.setPosition(this.node.position.x, this.node.position.y, value);

shader部分:
CCProgram sprite-vs %{

out float wh_rate;

         wh_rate = a_position.z;
         ..............

    CCProgram sprite-fs %{
       ........ 
         in float wh_rate;

    //半径羽化圆形alpha

      float smoothAlpha(vec2 vec,float radius){

          return smoothstep(radius,radius - radius * 0.1,length(vec));

      }

      vec4 batch(){

        //uv半值

        vec2 uv_half = vec2((color.g - color.r)/2.,(color.a - color.b)/2.);

        //中心点uv

        vec2 center_uv = vec2(color.r + uv_half.x,color.b + uv_half.y);

        //将uv偏移到中心点

        vec2 uv = uv0 - center_uv;

        float radius ;

        //根据宽高比进行uv的缩放

        if(wh_rate > 1.){

          uv.x /= wh_rate;

          radius = uv_half.y;

        }else{

          uv.y *= wh_rate;  

          radius = uv_half.x;

        }

        //根据半径羽化圆形alpha

        float alpha = smoothAlpha(uv,radius);

        //uv偏移回来

        uv += center_uv;

        //根据新的uv进行采样

        return vec4(texture(cc_spriteTexture, uv).rgb,alpha);

      }

      vec4 unbatch(){

        //将uv偏移到中心点

        vec2 uv = uv0 - .5;

        vec2 vec = uv;

        //根据宽高比进行uv的缩放

        //float target ;

        if(wh_rate > 1.){

          uv.x /= wh_rate;

        }else{

          uv.y *= wh_rate;  

        }

        //根据半径羽化圆形alpha

        float alpha = smoothAlpha(vec,.5);

        //uv偏移回来

        uv += .5;

        //根据新的uv进行采样

        return vec4(texture(cc_spriteTexture, uv).rgb,alpha);

      }

      vec4 frag () {

        if(color.g <= 0.){

          return unbatch();

        }else{

          return batch();

        }

      }
2赞

大神,我也遇到同样的难题,能不能提供一个完整代码,一个demo就好,我现在也需要解决,不知道怎么做,谢谢