接上一篇2D描边-内描边
前言
在上一篇中,我们介绍了内描边的方法,也同时阐述了内描边的优缺点,如果你对那些缺点非常在意,那本篇的外描边也许是你的救星,但同时,你也要承担它的缺点,就是没那么轻度了。话不多说,咱们看看外描边和内描边的天差地别。
原理
既然是外描边,那就不是占用原图的像素画边了,而是在原图外围描上一圈,既然不占用原图像素,那也就不是在它的材质中做文章了,而是要用到后处理。(有关自定义后处理的部分本文章不做介绍,官方以及相关文章很多,我后面给出参考链接)我们要额外有个相机,让它单独照我们需要描边的物体,然后在这个相机照的图上去找边,把边扩大一圈,赋上我们的描边色,再把这些描边单独扣出来,得到一张只有描边的图,再把这个图与主相机的绘制结果做融合,那就得到了你想要的效果,如上图所示,我只描了中间那棵树的边。
描边Camera
所以第一步,就是创建描边Camera,这一步比较简单,我只想让中间那棵树描边,那我就创建个Layer,命名为OUTLINE,赋给那棵树的Layer,然后让描边Camera的Visibility只为OUTLINE,这样它就只照中间那棵树了。同时不要忘了,我们的主相机的Visibility也要加上OUTLINE,不然它就照不到中间的树了。
描边Camera
主Camera
自定义后处理
在Camera只照到描边物体后,我们在自定义后处理前就得到了一张RenderTexture,简称描边rt,那么怎么通过这张rt去描边呢。还记得上一篇吗,我们通过图的Alpha去找边,那时是判断图的周边像素是否有Alpha为0的像素。在这里,我反其道而行之,你想想,这张rt有什么特点,除了树的部分Alpha是大于0的,其余部分Alpha是0,那么我是不是可以把树边缘外面一圈的像素的Alpha也变成大于0呢,这样相当于把树扩大了一圈,然后再把中间树的部分Alpha变成0,是不是就只剩扩大这一圈的部分了,这就是我们想要的东西。
所以核心首先是扩大一圈,我上面说了和上一篇的是反其道而行之,上一篇是找像素周边的最小Alpha,这里呢,就是找像素周边的最大Alpha,你想想,在树外面Alpha为0的部分,如果它周边有一个像素的Alpha不为0,说明什么,说明这个像素挨着树,那它就是我们要的轮廓。
如图算法,核心就是这么简单,baseUv是当前像素uv,extendUv是偏移uv,maxAlpha是传进来的最大Alpha,先通过偏移uv得到它周边的这个像素的uv,这里有个新鲜的东西,就是cc_nativeSize,它是系统内置的vec4变量,xy是屏幕的宽高,zw就是宽高的倒数,也就是屏幕rt的纹素,所以我们终于摆脱了上一篇中要传图的纹素的问题。_OutlineSize是描边宽度。_OutlinePPRt是后处理之前的原图,就是我们描边Camera的rt图。得到这个周边像素的Alpha后,和传进来的maxAlpha做比较,返回最大的Alpha,这样我们就能找到周边有Alpha大于0的像素了。
这就是遍历当前像素周边8个偏移uv的Alpha的部分,最后得到最大的Alpha。好,现在就已经完成扩一圈的任务了。然后我们要抠去中间树的部分了,这个很简单,我们直接拿扩完的Alpha减去原图的Alpha,就剩外轮廓的Alpha了。
这个aExtend就是扩展Alpha,如果大于0,就是描边,那我们给该像素上描边色,并且Alpha为1,否则就不是,给黑色,Alpha为0。大概如下所示。
以上是自定义后处理的shader部分,ts代码部分平平无奇,就是把描边宽度和描边色传给shader就行。
最后我们把描边Camera的结果输出到一张我们自定义的描边rt中。
融合
在得到了以上的描边rt,我们就要拿它与主Camera做融合了。cocos已经给我们提供了BlitScreen的后处理,只需要提供我们自定义的shader和材质就可以做融合了。
上面的outline-rt就是我们的描边rt。shader很简单
inputTexture是系统传给我们的当前Camera的图,也就是我们主相机照到的所有东西。_BlendTex就是上面的outline-rt,也就是描边rt,我们根据描边rt的Alpha做俩图的融合,没有描边就用原图色,有就用描边色,仅此而已。最后就得到了一开始那张图。
优缺点
说了这么一大通,缺点就是复杂了点。需要自定义后处理。同时也不能不同物体上不同的描边色,除非你多定义几个后处理,这显然对性能不太友好。
但优点明显啊,不论你想描多少边都一次绘制成型,也不用考虑上一篇图集的问题,小窟窿的现象也会少很多。所以看你取舍了。
参考
Cocos Creator 3.8 后期效果 Shader 编写(2/2) 进阶篇
引流
我的前作:2D光影系统,有兴趣可以看看。
2D光影系统-光源一全局方向光
2D光影系统-光源二Sprite光
2D光影系统-阴影