Unity下的日式卡通渲染实现-描边篇(三)

这边文章讲述的是项目中用到的一些卡通渲染描边相关技术。

一、Back Face外扩描边

背面外扩描边和后处理描边是卡通渲染中主要应用到的描边方式。

1.1 实现原理

第一个Pass正常渲染物体。第二个Pass只渲染背面,同时顶点沿着法线方向偏移,开启深度测试。
第二个Pass开启深度测试的用处一个是重叠部分不会显示出来,另外可以利用Early-Z减少需要处理的片元数量。

1.2 描边的法线优化

由于我们是沿着法线偏移顶点,那么最终的描边结果对法线的依赖很大。如果法线分布有问题,可能造成描边断裂的情况。如下图所示:

这是因为四个面的法线都是垂直于面的,在角的地方没有连续性。一种比较好的解决方式是计算平均法线存储在不使用的uv通道内,比如uv8,然后使用这个平均法线去计算描边。
何谓平均法线?即顶点周围面法线的平均或者加权平均。
如何计算这个平均法线了?这个可以编写外部工具对fbx直接离线修改;或者编写Unity的脚本修改uv8,不过在Unity内已经修改不了Fbx文件了,所以去修改Mesh的uv8数据,实际上这个修改是存储在工程的缓存数据内的,因此需要给Mesh新增一个Tag,如果有这个Tag导入Mesh的时候就需要就需要计算平滑法线。

1.3 根据摄像机修正描边宽度

一个是距离摄像机的距离,理论上来说应该是距离摄像机越远描边应该越小,这个可以用摄像机空间的z值来表示。另外一个是Fov,Fov越大描边应该越小。
加入这2个修正因子后,描边的粗细会看起来自然很多。

1.4 描边深度偏移控制消隐

有些地方美术实际上不希望出现描边。比如,头发的中间部位,美术只希望头发的边缘能看到描边。但是,正对着角色的时候,头发的中间部分实际上也是外扩的边缘,同样会看到描边。
这种情况可以通过使用深度偏移来修改顶点着色器的裁剪坐标,从而消隐描边。实际上,就是把不需要看到的描边往里推,从而被角色本身覆盖,就看不到描边了。
那么,哪些描边需要消隐了?就是下面要说的顶点色。

1.5 顶点色控制描边宽度和深度偏移

我们提供了顶点色的两个通道来分别控制描边的粗细和深度偏移。粗细很好理解,就是有些部位描边宽有些更窄。深度偏移就是上面说的消隐问题,有些地方的描边希望看不到就可以增加一定的深度偏移使其被角色挡住。
顶点色需要美术使用DCC工具去涂色,或者也可以在Unity中使用编辑器去涂,然后保存下来。还是类似的问题,在Unity中不能修改原始的Fbx文件,因此涂色后的网格数据只能保存为.asset。
当前项目中使用的是这篇文章:在Unity中写一个简单的顶点颜色编辑器的顶点色工具,基本需求能够满足。

最终的描边效果如下所示:
卡通渲染外扩描边
可以看到头顶的头发通过顶点色深度偏移控制了消隐,头发的描边粗细也是通过另一个顶点色通道控制的。

二、 后处理描边

后处理描边是在图像空间使用边缘检测因子得到边缘信息,通常是检测深度图或者法线图,比颜色图效果更好。因为,深度或者法线在角色边缘有明显的不连续性。但是,后处理描边的缺点是无法控制描边或者说很难像外扩描边一样精细的控制描边效果,同时还会把内描边也检测出来。
对于头发的描边,后处理描边这些缺点就是非常致命的,因为我们主要用的还是外扩描边。

三、其它描边方式

3.1 NdotV

类似简单的边缘光实现方式,也可以用来做描边,但是效果和控制力度肯定是达不到需求的。

3.2 深度贴图描边

之前说的深度贴图边缘光和阴影同样可以用来做描边,也能使用顶点颜色提供一定的控制粒度,比如控制粗细,但是也无法做深度偏移消隐等。

四、内描边

所谓内描边,指的是物体内部的描边,非物体边缘看到的描边。之前说的技术基本上都是针对外描边的。

4.1 本村线

简单来说,是直接在贴图上画描边,同时这些描边基本是跟轴对齐的。不过工作量很大,而且很大细节需要控制,很少有美术愿意采用这种方式,因此不做过多的讨论。
如下图:
!](https://raw.githubusercontent.com/xpc-yx/markdown_img/master/小书匠/本村线描边.jpg)

4.2 后处理内描边

网上有文章提到二之国中的做法是在顶点属性通道中记录边缘程度,然后在后处理中来进行绘制内描边。
如下图所示:

猜测是类似于顶点色的方式,让美术使用工具在顶点色中涂色边缘程度,
然后需要一个Pass将顶点色上的边缘程度属性输出到一个RT上,最终在后处理Pass中检测这个RT对应像素的边缘程度完成内描边。
至于如何将边缘程度转换为描边,需要参考相关资料才能弄清楚了,这里的日文看不懂啊。

五、参考资料

【01】从零开始的卡通渲染-描边篇
卡通渲染学习总结