这是一个在九宫格基础上使用shader画出的半透明亮线。至于如何在九宫格特性sprite上面进行均匀画线,请看另一篇文章:
CocosCreator Effect (Shader) - 反九宫格补偿
当然,这张图如果没有经过打包,所取得的结果是正常的。但是一旦进入图集打包,则会得到左图的错误结果。
处理方式1:
把这张图的Packable取消勾选,就是这张图不会进入打包即可得到正确结果。 至于在图集反正是一个effect去处理的,对DrawCall反正都要+1,在图集去除这张图也没什么不好的。
但是这个图的大部分多数情况仍需按常规显示。好吧。那我复制一个图呗。shader的用独立复制出来的额外一张小图去除packable勾选即可。
那这里我就钻个牛角尖,我就要直接使用在图集中的这张图去做effect,那么,我就需要来个针对图集中位置的反变换,把图集范围内的uv坐标还原到只表示这张图的uv [0,1]内。
如果看过反九宫格补偿这篇文章。那么应该对反变换有一定的感觉了。
反Packable变换
这次使用spriteframe的属性uv:
如果直接在start里面查询:
看这里的全是0或者1,没有表示出来其在大图中的位置。而实际上,你是需要把它放进图集才可以看见。如果是动态图集。引擎运行时会生成这个图集,因此这个图在大图中的位置会随着大图的变化而变化。那么我是在启动后等了10帧再去拿这个数组的(而且在实际使用时,你也需要等整个大图固定出来了之后才能拿这些数据进行计算,一般来说这个大图确实已经固定了,除非是动态图集要注意一下,稳定才能拿,或者动态图集中的图就不要用这个变换):
同样的这8个值同样也是表示的4个点,这4个点恰好是一个长方形,围出了小图在大图中的标准位置(我习惯把[0,1]之间的值叫做标准值,标准位置)
这里直接说结论:
其中的uv[0],uv[6]就是小图在大图中的左右两边界位置
其中的uv[7],uv[1]就是小图在大图中的上下两边界位置
那么对应给material这样传值:
let uv: number[] = this._sprite.spriteFrame.uv;
material.setProperty('u_lrbt', [uv[0], uv[6], uv[7], uv[1]]);
进入effect文件中这样去处理:
vec2 uvsc = vec2(v_uv0.x, v_uv0.y);
#if USE_PACKABLE_CONFRONT
uvsc.x = linear(u_lrbt[0], u_lrbt[1], 0.0, 1.0, uvsc.x);
uvsc.y = linear(u_lrbt[2], u_lrbt[3], 0.0, 1.0, uvsc.y);
#endif
到此,普通的一个在图集中的图就如同不打包的单图一样去处理uv,使用uvsc即可。
同时兼容反九宫格的补偿
由于有反九宫格补偿那篇文章,会发现图集中的图放进来做九宫格就会产生问题。
即使是如上使用了uv的反packable变换。
原因在于:
uvSliced,也就是传入的uvs,也会收到图集的影响。那篇文章讲的是单图。
解决方式很简单,针对传入的uvs,也如同uv一样做一次反packable变换。
改造后的代码:就是把u_uvs变换为uvs。
不做这个操作会是这样的:
vec2 uvsc = vec2(v_uv0.x, v_uv0.y);
#if USE_PACKABLE_CONFRONT
uvsc.x = linear(u_lrbt[0], u_lrbt[1], 0.0, 1.0, uvsc.x);
uvsc.y = linear(u_lrbt[2], u_lrbt[3], 0.0, 1.0, uvsc.y);
#endif
#if USE_SLICED_CONFRONT
vec4 uvs = vec4(u_uvs[0], u_uvs[1], u_uvs[2], u_uvs[3]);
#if USE_PACKABLE_CONFRONT
uvs[0] = linear(u_lrbt[0], u_lrbt[1], 0.0, 1.0, uvs[0]);
uvs[1] = linear(u_lrbt[0], u_lrbt[1], 0.0, 1.0, uvs[1]);
uvs[2] = linear(u_lrbt[2], u_lrbt[3], 0.0, 1.0, uvs[2]);
uvs[3] = linear(u_lrbt[2], u_lrbt[3], 0.0, 1.0, uvs[3]);
#endif
vec4 un = vec4(0, uvs[0], uvs[1], 1.0);
vec4 vn = vec4(0, uvs[2], uvs[3], 1.0);
float rx = 0.0;
float ry = 0.0;
if (uvsc.x < uvs[0]) {
rx = linear(un[0], un[1], u_ur[0], u_ur[1], uvsc.x);
} else if (uvsc.x < uvs[1]) {
rx = linear(un[1], un[2], u_ur[1], u_ur[2], uvsc.x);
} else {
rx = linear(un[2], un[3], u_ur[2], u_ur[3], uvsc.x);
}
if (uvsc.y < uvs[2]) {
ry = linear(vn[0], vn[1], u_vr[0], u_vr[1], uvsc.y);
} else if (uvsc.y < uvs[3]) {
ry = linear(vn[1], vn[2], u_vr[1], u_vr[2], uvsc.y);
} else {
ry = linear(vn[2], vn[3], u_vr[2], u_vr[3], uvsc.y);
}
uvsc.x = rx / u_ur[3]; // linear(0.0, u_ur[3], 0.0, 1.0, rx);
uvsc.y = ry / u_vr[3]; // linear(0.0, u_vr[3], 0.0, 1.0, ry);
#endif