前言

本文中所讲述的描边方法基本基于后处理所实现,是本人学习过程中的一些总结,各位前辈大佬若有更好的方法,还望指点。本文若有论述错误,还望斧正。

一直以来对卡通渲染(Cel Shading)有着非常浓厚的兴趣,而卡通渲染中描边是非常重要的一环,描边质量的高低一定程度上决定了卡通渲染在视觉效果上是否出彩。卡通渲染属于非真实感渲染(Non-photorealistic rendering,简称NPR)。与之相对应的则是真实感渲染(Photorealistic rendering),卡通渲染更多的在追求风格化的表现,所以或出现不符合物理规则的现象,而真实感渲染则严格按照物理规则渲染(Physicallly-Based Rendering,简称PBR)。回归正题,本文基于后处理的描边相对不容易进行定制,这里展示一些思路。

方法一:使用翻转后的模型进行描边

效果如下
Alt text
这种描边通过复制一次模型并将复制的模型进行法线反转并开启背面剔除(UE4默认开启背面剔除),然后将反转后的模型放大一点并与原模型重合得到轮廓形成描边效果。

创建Outline材质

Alt text
需要将材质改为Mask并且改为无光照(Unit),同时将双面打开
Alt text
描边的固有色一般设置为黑色。TwoSideSign节点用来进行法线的反向。TwoSidedSign节点是一个常量表达式,对正面输出1,对反面输出-1,我们知道模型的正反面由法线的朝向决定,所以我们乘以负一,现在表示的就是模型的背面
Alt text
然后我们需要将模型沿法线方向放大,所以使用顶点法线乘以一个常量OutlineWidth控制缩放(描边大小),连接在世界位置偏移WPO上对顶点进行偏移
Alt text
这样我们就完成了一个十分简单的描边材质。但是描边宽度会随着分辨率的大小而变化,我们接下来处理这个问题。想要依据屏幕分辨率的大小保持描边宽度的比例不变。就需要Viewsize节点,该节点输出的是当前屏幕的大小(一个二维向量)。计算相机位置与绝对世界位置的距离然后除以Viewsize再与常量OutlineWidth相乘,这样我们的描边宽度就会依据分辨率的大小而保证比例不变
Alt text
然后我们发现在我们距离模型非常远的时候,描边就会显得非常多余,所以我们需要在一定距离后移除物体的描边,而这一点可以用Pixel Depth来实现
Alt text
Alt text
Alt text
PixelDepth表达式输出当前被渲染的像素的深度或到摄像机的距离。因为想实现消失距离随着描边宽度变化的效果,所以将OutlineWidth与深度做了相除,并用原OutlineWidth减去基于像素深度计算后的OutlineWidth,使用clamp将范围限制在0-10内,最后通过乘法与依据分辨率的描边宽度结合起来

方法二:使用卷积进行边缘检测绘制描边

理解图像卷积操作的意义
边缘检测算法
这里直接贴文章(直接学的)讲的易懂
Alt text
这里注意需要改为色调映射前,否则会出现屏幕抖动的问题

方法三:使用SceneDepth进行描边

Alt text
SceneTexelSize表达式通过texel大小来偏移,以此避免在较低分辨率下的结果不一致。Outline Width Depth表示偏移量的大小,我们需要对UV分别进行偏移,因此分别mask出来R通道与G通道并增加一个维度(R通道,0)、(0,G通道)用来进行运算
Alt text
将偏移后的SceneTexelSize与ScreenPosition相加然后对场景深度进行采样。我们需要上下左右四个方向,所以左和上需要乘以-1再进行采样
Alt text
使用没有偏移ScreenPosition的UV采样的SceneDepth依次减去偏移上下左右后的SceneDepth并将4个结果相加使用Power节点让描边更加平滑
Alt text
将这个结果作为Lerp的Alpha输入,PPI0表示的就是场景颜色,但他是一个四维向量,所以需要把RGBmask之后使用
Alt text
Alt text
Alt text
Alt text
但是这样我们所有的物体都会产生描边,但我们并不想所有的物体都产生描边,所以我们可以使用自定以深度来控制那些是我们想要描边的物体,那些使我们不想要描边得物体
Alt text
Alt text

方法四:使用WorldNormal进行描边

只需要将上面SceneDepth全部修改为WorldNormal即可
Alt text
效果如下
Alt text
Alt text
最后我们可以将SceneDepth描边与WorldNormal描边加起来使用
Alt text