
效果如上。
实现的原理:加载远程图片符合动态合图功能就会合到图集里,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();
}
}