本文是《Unreal Engine 4 渲染目标(Render Target)教程 之 动态网格绘制(Dynamic Mesh Painting)》的下半部分,上半部分请见《Unreal Engine 4 渲染目标(Render Target)教程 之 动态网格绘制(Dynamic Mesh Painting)(上)》
作者|Tommy Tran Sep 7 2018 | 翻译 开发游戏的老王

本教程的方法

Ryan的方法是可行的,但它的实现方法略繁琐:

  • 需要两次对渲染目标的绘制。第一次用于捕获展开的网格,第二次用于累加球形遮罩。
  • 一个渲染目标存储世界位置。
  • 一个渲染目标累加球形遮罩,而且我们需要为每一个要绘制的角色配一个独立的渲染目标。

本教程的方法舍弃了第二次绘制和用于存储世界位置的渲染目标。其实现原理是将展开和球形遮罩图组合存储到一个展开材质中(unwrap material)。然后在叠加合成模式(additive composite mode)中捕获展开并将球形遮罩累加上去。

需要注意的是,两种方法都是在模型的UV没有重叠的时候效果最好。因为重叠的UV意味着一些像素会共用UV空间,并且也会共用遮罩。例如,我们让角色的双手的UV重叠在一起,如果一只手被遮罩了,那么另一只手也会被遮罩。

大致了解了这个方法,我们来创建展开材质。

创建展开材质(Unwrap Material)

Materials文件夹中创建新的材质并命名为M_Unwrap,然后打开它。

接下来,修改如下设置:

  • Shading Model: Unlit,确保scene capture不捕获任何光照信息。
  • Two Sided: Enabled,有些时候展开的UV面会反向,所以开启Two Sided以后,就能够确保即使有面反转了也能被看到。
  • Usage\Used with Skeletal Mesh: Enabled,编译用于骨骼网格材质的必要着色器。

在这里插入图片描述
接下来,对网格展UV。创建如下节点。笔者在MPC_Global资源中已经创建了CaptureSizeUnwrapLocation变量。

在这里插入图片描述

上述代码将为网格以指定的位置和大小来展UV。注意,如果你的网格UV在另外的通道,你需要修改TextureCoordinate节点的Coordinate Index。比如,UV在通道1,则将Coordinate Index设为1

接下来,创建球形遮罩。我们需要2个参数:碰撞位置(hit location)和球的半径(sphere radius):

在这里插入图片描述

上述代码将为球形遮罩范围内的像素返回白色,为其范围之外的像素返回黑色。先不用设置参数的值,我们会在后续的蓝图中做这件事。

一定要将Absolute World Position node节点设为Absolute World Position (Excluding Material Shader Offsets)。因为像素的世界位置会因展UV而发生改变。排除材质的偏移量会给我们展UV之前的原始世界位置。

以上就是创建展开材质的全部工作。点击Apply然后关闭材质。接下来我们将材质应用到角色上,并将其展UV。

为角色展UV

本教程中scene capture蓝图将负责展UV和捕捉。首先,我们需要一个展开材质的动态实例。在Blueprints 文件夹中打开BP_Capture。然后为Event BeginPlay事件添加如下高亮节点。确保将Parent设为M_Unwrap

在这里插入图片描述

接下来,我们需要一个函数实施展UV和捕获。创建一个名为PaintActor的函数。然后为其添加如下参数输入:

  • ActorToPaint: 类型是Actor,被展UV和捕捉的角色。
  • HitLocation: 类型是Vector,球形遮罩的中心。
  • BrushRadius: 类型是Float,球形遮罩的半径(世界单位)。

在这里插入图片描述

尽管该方法适用于任何actor,但是我们还是要检查一下输入的actor是否为Character。简单起见,我们把角色的骨骼网格存储到一个变量中,因为我们要访问它很多次:

在这里插入图片描述
接下来,实现展UV和球形遮罩。在节点链的最后添加如下高亮节点:

在这里插入图片描述

解释以下上述代码:

  1. 先保存网格的原始材质(后续我们会将它重新应用到网格上),然后应用展开材质。
  2. 第二行会把碰撞位置和笔刷半径传给展开材质。

在测试展UV之前,我们需要从玩家角度做一次射线检测以获取碰撞位置。

获取碰撞位置

点击Compile并回到主编辑器,打开BP_Player,找到Shoot函数并添加如下高亮节点。本教程中,将Brush Radius设为10

在这里插入图片描述
点击Compile并关闭BP_Player。点击Play然后在角色上单击左键,就可以展UV并进行遮罩了。

在这里插入图片描述

你可能很奇怪,为什么遮罩总在动,因为角色的身体相对于球形遮罩,总是进进出出的。但这不算是问题,因为我们仅会在碰撞的瞬间捕获展开。

现在我们已经展开了网格,接下来该捕获它了。

捕获展开

首先,在被展开网格前面添加一个unlit的黑色平面以挡住UV壳边缘上的接缝。打开BP_Capture添加一个Plane并命名为BackgroundPlane。为节省时间,笔者已经创建好了黑色材质。将材质设为M_Background

在这里插入图片描述

本教程中,展开和捕捉大小为500×500个单位,这也是背景平面的最小尺寸。将背景平面的Scale 设为 (5.0, 5.0, 1.0)

在这里插入图片描述

因为平面的位置和展开的位置是相同的,所以最好将平面的位置下移一些,以防止它们在Z轴上冲突(z-fighting),将BackgroundPlaneLocation设为 (0.0, 0.0, -1.0)

接下来,执行捕捉。回到PaintActor函数,并添加如下高亮节点:

在这里插入图片描述

上述代码会捕捉展开的网格。然后重新应用网格的原始材质。

我们需要确保scene capture向渲染目标“添加”内容,而非覆盖掉先前的内容。因此,选择SceneCapture组件,然后将Scene Capture\Composite Mode设置为Additive
在这里插入图片描述
点击Compile并关闭蓝图。接下来,我们要在角色材质中使用渲染目标。

使用遮罩

Characters\Mannequin\Materials中打开M_Mannequin。然后添加如下高亮节点,并确保
Texture Sample设为RT_Capture

在这里插入图片描述

实现的结果就是,遮罩为白色的地方显示为红;遮罩为黑色的地方显示为橘黄。如果你愿意,还可以使用这个遮罩把纹理或材质层混合起来。

点击Apply并关闭材质。点击Play然后用左键在角色身上点击,就开始绘制了。

在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐