1. 矢量场
矢量场只是一个纹理,其中每个像素代表一个方向。让我们看看如何将方向存储到纹理中。看看这个网格:
设红点是要移动的对象。如果把它移到右下角,什么向量代表这个运动?答案是(1, 1)!还可以将矢量表示为颜色,这就是将它们存储到纹理中的方式。
右下象限看起来不错,因为它在两个轴上都有渐变。这意味着可以将该象限中的任何向量存储为颜色,因为每个向量都有唯一的颜色。
但其他三个象限是有问题的。它们仅在一个轴上有渐变或根本没有渐变。这意味着多个向量将共享一种颜色。例如,将无法区分向量**(-1, 1)和(0, 1)**。
这三个象限不是每个向量都具有唯一颜色的原因是:只能使用 0 到 1 之间的值来表示颜色。但是,三个象限使用超出该范围的负值。
解决方案是重新映射向量,使它们适合 0 到 1 的范围。我们可以通过将向量乘以0.5然后加上0.5 来实现。这是它的外观的可视化:
以下是几种颜色以及它们在重新映射后代表的方向:
- (0, 0): 负 X 和 Y
- (0.5, 0.5): 没有移动
- (0, 1): 负 X 正 Y
- (1, 0): 正X和负Y
1.1 创建矢量场
与雪道不同,我们不会捕捉到物体的形状。相反,我们将使用 "刷子 "在渲染目标上作画。这些笔刷将是自定义矢量场的图像。业界把这些画笔称为方向画笔。
我们可以使用粒子,来代替使用蓝图(Blueprints)绘制到渲染目标上。粒子将显示方向刷并从玩家处发射出来。为了创建矢量场,我们只需使用场景捕捉,并只捕捉粒子。这种方法的优点是,它非常容易创建轨迹。它还允许我们轻松地控制属性,如轨迹持续时间和大小。粒子还可以创建半永久性的轨迹,因为它们在离开和重新进入捕捉区域后仍然存在。
下面是几个我们可以使用的方向刷的例子以及它们对草地的影响。注意,在下面的例子中,粒子是不可见的。
2. 创建方向材质
有两种方法来创建一个方向刷。
- 数学。在材料中定义方向和形状。这样做的好处是不需要外部软件,对于简单的形状来说很容易。
- 转换法线图。要转换为可用的矢量场,我们只需要去掉蓝色通道。这种方法的好处是:可以很容易地创建复杂形状。
我们将以数学方式创建一个。导航到材料文件夹,打开M_Direction
。注意,这个材料的着色模型是无光的。这很重要,因为这将允许场景捕捉在没有光线影响的情况下捕捉粒子。
为了保持简单,我们将创建一个材料,使草从粒子中心移开:
现在需要进行重新映射:
接下来,让我们给它一个圆形:
RadialGradientExponential
是控制圆的大小和硬度的东西。将其与粒子颜色相乘将允许我们从粒子系统中控制粒子的不透明度。
下面是画笔的样子。
3. 创建轨迹粒子系统
导航到ParticleSystems
文件夹并打开PS_GrassTrail
。我创建了需要的所有模块:下面是每个模块如何影响草径的情况。
Spawn
。spawn rate
会影响规矩的平滑程度。- 生命期。草地恢复到默认状态之前的痕迹持续时间。
- 初始大小
color over life
。由于我们在材质中使用了粒子颜色,我们可以在这里控制不透明度。我们还可以调整阿尔法曲线来控制痕迹的消退。例如,我们可以做线性渐变,缓进和/或缓出。在本教程中,我们将把它保持在默认状态,即线性渐变。- 锁定轴:用于确保粒子朝向场景捕捉。
- 初始旋转。用来确保粒子朝向正确的轴线。
首先,我们需要设置材料。选择 "Required "模块,然后将材料设置为M_Direction
。也将排序模式设置为PSORTMODE Age Newest First
这种排序模式将确保较新的粒子将在较旧的粒子之上渲染。如果我们不这样做,老的粒子可能会影响到草地而不是新的粒子。接下来是痕迹的持续时间。选择Lifetime
模块并将Constant
设置为5。这将导致痕迹在五秒钟内逐渐消失。
接下来是大小。选择Initial Size
模块并将常数设置为(150, 150, 0)
。这将使每个粒子覆盖一个150×150
的区域。
现在我们需要确保粒子朝向场景捕捉。由于本教程中的场景捕捉是从上面捕捉的,所以粒子需要面向正的Z轴。要做到这一点,选择Lock Axis
模块,并将锁定轴标志设置为Z
。
⭐️最后,我们需要设置粒子的旋转。目前,画笔中的颜色并没有与它们所代表的方向对齐。这是因为在默认情况下,粒子系统会应用90度的旋转。为了解决这个问题,选择初始旋转模块并将常数设置为-0.25
。这将使粒子逆时针旋转90度。
4. 附加粒子系统
导航到Characters\Mannequin
并打开BP_Mannequin
。之后,创建一个Partice System
组件并命名为GrassParticles
。
如果玩家能在游戏中看到踪迹,那就太奇怪了,所以最好将其隐藏起来。要做到这一点,启用 Rendering\Owner No See
现在,场景捕捉被设置为捕捉一切。很明显,这是不好的,因为粒子是唯一应该影响草地的东西。在下一节中,将学习如何只捕获粒子。
5. 只捕获粒子
如果我们现在捕捉粒子,我们会在没有粒子的地方得到不想要的弯曲。这是因为渲染目标的背景颜色会是黑色。弯曲的发生是因为黑色代表了向负XY轴的运动(重新映射后)。为了确保空白区域没有运动,我们需要确保渲染目标的背景颜色是(0.5, 0.5, 0)
。一个简单的方法是创建一个巨大的平面,并将其附加到玩家身上。
首先,让我们为背景创建材质。打开Materials/M_Background
。之后,将一个(0.5, 0.5, 0)的常数连接到Emissive Color。
注意:就像粒子材料一样,我们计划捕捉的任何材料都需要
unlit
。
回到BP_Mannequin
,然后创建一个新的Plane
组件。将其命名为 “Background”。设置如下参数:
隐藏它,启用Rendering\Owner No See
。
5.5 使用仅显示列表
在我们可以添加到只显示列表之前,我们需要一个方法来获得所有受草影响的actor
。做到这一点的一个方法是使用标签。标签是我们可以分配的简单字符串。然后我们可以使用Get All Actors With Tag
节点来获得所有带有某个标签的actor
。
因为玩家角色应该影响草地,所以它需要一个标签。要添加一个标签,首先点击类别默认按钮。然后,在Actor/Tags
下创建一个新标签,并命名为GrassAffector
。(这里错了,应该是给角色蓝图加一个tag
):
由于只显示列表只接受组件,我们也需要给受草影响的组件添加标签。选择GrassParticles组件,然后添加一个位于
Tags
部分下的新标签。把它也命名为GrassAffector(我们不需要使用这个标签)。对 "背景 "组件做同样的事情。
现在我们需要把所有影响草地的组件添加到捕获的只显示列表中。打开Blueprints/BP_Capture
。转到Event BeginPlay
,并添加:
这将循环检查所有带有GrassAffector
标签的actor
。然后它将检查该actor
是否有任何具有相同标签的组件,并将它们添加到只显示的列表中。
接下来我们需要告诉场景捕捉使用只显示的列表。选择SceneCapture组件,然后转到Scene Capture部分。设置原始渲染模式为 Use ShowOnly List
。
6. 压倒草
首先,我们需要将渲染目标投射到草地上。转到Materials
文件夹,打开M_Grass
。然后,创建下面的节点。确保将纹理设置为RT_Capture
。
由于我们已经将颜色重设为
[
0
,
1
]
[0,1]
[0,1],我们需要在使用它之前将它重设为
[
−
1
,
1
]
[-1, 1]
[−1,1]:
现在有了弯曲方向,需要一些方法来使草向这个方向旋转——一个叫做RotateAboutAxis
的节点。让我们从NormalizedRotationAxis pin
开始。顾名思义,这是顶点将围绕其旋转的轴。为了计算这个,我们需要将弯曲方向与(0, 0, -1)
做叉积:
接下来是旋转角度。默认情况下,它期望的数值在0和1之间,其中0是0度,1是360度。为了得到旋转角度,我们可以使用弯曲方向的长度乘以最大旋转量:
计算PivotPoint
有点棘手,因为一个草网包含多个草叶。这意味着我们不能使用类似于Object Position
节点的东西,因为它将为所有的草叶返回同一个点。
理想情况下,我们会使用3D包来存储UV通道内的pivot point
。但在本教程中,将只是近似地使用一个pivot point
。这样做的方法是:简单地从顶部向下移动一定的偏移量:
在本教程中,草的高度约为80个单位,这就是为什么将PivotOffset
设置为这个值。
接下来,将需要执行两个mask
。第一个mask
将确保草叶的根部不会移动。第二个mask
将确保捕捉区域外的草不会受到矢量场的影响。
7. Mask
在本教程中,已经设置了草的顶点颜色,使底部顶点是黑色的,顶部顶点是白色的。
第一个mask
,只需将RotateAboutAxis
的结果与顶点颜色节点相乘:
第二个mask
,也很简单:
8. 捕捉相机跟随主角
这个和我的 教程2[交互雪] 的做法是一致的,所以这里就不重复了,请读者移步教程2,去做这部分的填充完善