UE4 描边
前言
- 本文引擎版本:
4.15 - 项目源码地址
不管在 RTS 或者 FPS 类型的游戏中,描边都是一个基础的功能。在 RTS 游戏中,对单位描边一般用来表示选中这个单位或者鼠标悬浮在这个单位上。在 FPS 游戏中,描边一般用在被建筑物遮挡的单位上,描述这个单位被遮挡部分的轮廓。
Depth Map
Depth Map 描述的是场景中的物体和摄像机之间的距离,距离越近,值越小,颜色越深。可以在显示模式中切换成 Scene Depth 来查看深度显示模式,如图

正常的场景

按深度显示的场景

Custom Depth Map
在游戏中,我们需要动态的显示/隐藏单位的描边,所以就要使用到自定义深度图(Custom Depth)来完成这个功能,因为 Custom Depth 只会渲染 Render CustomDepth Pass 属性为 True 的单位,所以我们可以通过控制这个单位的 SkeletalMeshComponent 中的 bRenderCustomDepth 属性来控制描边,如下图所示,只有一个单位渲染到 Custom Depth 中

PostProcessVolume
要实现描边的功能,基本步骤是实现一个后处理描边材质,创建一个 PostProcessVolume,将后处理材质应用到这个 Volume中,打开要描边的单位的 Render CustomDepth Pass 属性。
首先拖动一个 PostProcessVolume 到场景中,如图

打开这个 PostProcessVolume 的 Unbound 属性,否则只有当摄像机处在这个 Volume 中的时候后处理材质才生效,如图

后处理材质
首先,创建一个材质,并修改这个材质为后处理材质,如图

示例:实现显示模式中的 Custom Depth 效果

将这个材质应用到 PostProcessVolume 中,如图

最终效果如图

为什么材质中要除以 5000
因为 SceneTexture 中的 CustomDepth 通道表示像素和摄像机之间的距离,这个值相对于颜色的范围区间 [0, 1] 显得非常大,所以要对这个值进行处理,使距离值落在 [0, 1] 之间,否则这个后处理材质只会得到一个全白的结果
描边材质
描边材质的核心功能就是检测物体边缘,而检测物体边缘有很多种方法,本文中使用 Sobel Operator 算法来进行检测
Sobel Operator 简述
对图片中的每一个像素,将其和其周围的八个像素值依次和 Sobel Operator 相乘,得到的结果值为这个像素的相对值,如图所示

Sobel Operator 分为水平和垂直两个方向,所以需要对每一个像素都执行水平和垂直两个方向的计算,再将得到的两个结果按照以下公式计算出最终的结果

Sobel Operator 两个方向的矩阵如下


根据和当前像素的偏移量来计算深度值
创建一个 Material Function MF_ExtraceDepth,有一个输入,为 Vector2,一个输出,为深度值,材质函数如图所示

计算九个深度值和Sobel算子的乘积
创建另一个材质函数 MF_ConvolveTexture,来计算乘积,有 9 个 Scalar 深度值输入,和 3 个 Vector3 输入用来表示 3 x 3 的 Sobel Operator 矩阵,输入材质函数如图所示

描边后处理材质
打开之前创建的后处理材质,调用 MF_ExtraceDepth 和 MF_ConvolveTexture 材质函数计算 Gx 和 Gy,如图

最终从 Gx 和 Gy 两个分量计算最终的深度相对值,并将结果和阈值进行对比,大于阈值就输出描边颜色,如图

最终效果
如图所示,打开 Render CustomDepth 属性后,单位就会被描边

描边抖动
在游戏中查看效果,会发现描边一直在抖动,根据文档 Temporal Anti-Aliasing or Why the GBuffer Jitters ,解决方法如下
