Unreal Engine 物体描边与高亮

发布时间 2023-12-17 17:22:51作者: ThomasZhong

  本篇随笔将使用 UE 中的后处理体积以及编写对应的材质参数,来实现物体的描边与高亮功能,要做到物体高亮与描边,需要利用到 UE 提供的 CustomDepth(自定义深度) 和 CustomStencil(自定义模板)两个 Buffer(亦或是在物理上占用一个Buffer,深度和模板占用位数不一样,但逻辑上可视为两个Buffer)。

一、物体高亮

  物体高亮的最简单的逻辑就是将需要高亮的物体写入 CustomStencil ,然后根据 CustomStencil 中的值,将被标记为需要高亮的像素位置混入需要高亮的颜色或是纹理,具体的实现方法如下:

1. 创建一个材质,取一个任意的名字,例如 M_PostProcess_Highlight,将该材质的材质域切换为【后期处理】,此时只有【自发光颜色】可以被连接;

 

2. 按下图所示构造节点并连接,ScreenPosition为屏幕的像素坐标,整体材质的表达含义为,查看当前像素位置是否被写入了大于0的自定义模板值,如果被写入则使用HighlightColor,否则使用原场景颜色;

 3. 保存这个材质,在编辑器的场景中拖入一个【PostProcessVolumn】,然后将该后处理体积对象的属性中的【无线范围(UnBound)】选中,即该后处理体积影响全部区域范围;然后在【后期处理材质】中添加刚才新建的材质【M_PostProcess_Highlight】

 

4. 将物体写入 Custom Depth / Stencil:选中场景中的任意物体(任意继承于 UPrimitiveComponent 的物体),按下图修改其渲染方式;

 5.  查看 CustomStencil 的缓冲区,检查是否物体模板值是否已被写入,若没有写入则需要在【项目设置】->【渲染】->【自定义深度/模板通道】中选择【启用模板】

 

 若有值则说明启用成功

 此时对应的效果如下,两个 StaticMesh 被高亮为绿色

 

二、物体描边

  物体描边相对于物体高亮需要多一步特殊的计算,即数字图像处理中的边缘检测算法,即我们需要在材质中自行实现一个边缘检测算法来决定那些像素是需要被描边的边缘像素,本例中使用拉普拉斯边缘检测方法作为示例。

1. 边缘检测:在图像处理领域,边缘检测一般用于寻找像素值具有梯度的像素位置,即某个像素位置的像素值与周边像素的像素值存在一定差异,可以判定这个像素为某个区域的边缘。拉普拉斯的卷积核如下方所示:

1   1  1

1  -8  1

1   1  1

因此基于对于模板缓冲区中的一个像素而言,我们需要知道其 3x3 范围内的全部像素值。新建一个材质函数 MF_LaplaceEdgeDetection,并加入以下节点与连线,横向与纵向的像素距离偏移量可以用下面的连接方式进行计算,OutlineWidth是描边的宽度。

 然后通过使用横向与纵向的偏移量,可以计算出九个像素位置的实际偏移量

 其中 GetCustomStencilOffset 的方法实现如下:其目的是获取一个屏幕位置加上某个偏移后的 CustomStencil 模板值。

 最后将取出的模板值按拉普拉斯卷积核加加减减,即可得到一个梯度计算结果,若梯度值 != 0,则说明该像素是边缘像素,需要执行额外的处理;

 2. 有了两个材质函数后,新建一个后处理材质 M_PostProcess_Outline,按下图添加节点

3. 将这个材质替换到后处理体积中的后处理材质中去,得到以下的结果:

 三、带深度的高亮/描边

如上图所示,上面的通过后处理的高亮与描边在运行时的实际效果会产生深度问题,可以看到红色线绘制在了玩家枪的前方,而实际上红色线应当被遮挡,因此需要额外考虑到深度剔除,材质中可以添加以下的节点来实现这个目的。

如果自定义深度大于场景深度,则说明被描边的物体被遮挡,因此不能通过后处理修改该像素位置的像素值,否则没有被遮挡,正常执行描边操作。

可以看到,经过上述过滤后,红色线不会绘制在玩家枪的前方;

 四、带深度的同时高亮与描边

只需要注意一下顺序,先做高亮后做描边,将材质按下图连接即可

完成啦!