直到最近,游戏中的草通常通过地面上的纹理来表示,而不是通过渲染单个茎来表示。 但是随着铁的力量的增加,渲染草成为可能。 在《
地平线零黎明》和
《塞尔达传说:旷野之息》等游戏中可以看到这种渲染的绝佳示例。 在这些游戏中,玩家可以在草地上漫游,更重要的是,草地可以
响应玩家的动作。
幸运的是,创建这样的系统并不是很困难。 实际上,本文将教您这一点! 在本教程中,您将学到以下内容:
- 使用场景捕捉和粒子系统创建矢量场
- 根据向量场弯曲玩家的草
注意:本教程假定您已经了解使用虚幻引擎的基础知识。 如果您不熟悉虚幻引擎,请查看我们的面向初学者的虚幻引擎教程系列,共十部分。 特别是,请查看“ 粒子系统”教程,以了解如何在本教程中使用Cascade。
注意:本教程是有关使用渲染目标的三个教程系列的一部分:
开始工作
让我们首先下载本教程的资料(您可以
从此处下载)。 解压缩它们,转到
InteractiveGrassStarter并打开
InteractiveGrass.uproject 。 您将看到一小片草地,这将是本教程的主题。 我还创建了一个小部件来显示场景捕获的渲染目标。
在开始之前,您应该学习
有关在雪中创建足迹的教程,因为我将跳过一些信息。 值得考虑的是,本教程中也使用了捕获和投影。 为了节省时间,我准备了一个蓝图捕获,类似于雪中轨道上的教程中的蓝图。
首先,让我们看一下创建交互式草的另一种方法。 最常见的方法是将玩家的坐标转移到草料上,并使用球形蒙版将草从玩家处弯曲到一定半径。
尽管这种方法非常好,但是当我们想在草地上添加更多参与者时,这种方法就无法很好地扩展。 对于添加的每个角色,都必须向材质添加另一个坐标参数和一个球形蒙版。 一种更可扩展的方法是使用
矢量场 。
什么是向量场?
向量场只是一个纹理,其每个像素对应一个方向。 如果您以前使用过流图,则它们是相似的。 但是,我们将使用“
世界位置偏移”接触来移动顶点,而不是移动UV。 与使用球形掩模的解决方案相比,要获得弯曲方向,材料只需对矢量场采样
一次即可 。
让我们找出如何在纹理中保存方向。 看一下这个网格:
假设红点是我们要移动的对象。 如果将其移动到右下角,那么哪个矢量将表示该移动? 如果您回答
(1,1) ,那么您是对的! 如您所知,您还可以将矢量表示为花朵,从而将其保存在纹理中。 让我们将此向量插入虚幻颜色选择器中,看看它返回什么颜色。
如您所见,方向
(1、1)返回黄色。 这意味着,如果我们想沿正XY轴的方向弯曲草,则必须使用此纹理颜色。 现在让我们看一下所有向量的颜色。
右下角的正方形看起来非常好,因为它的两个轴上都有渐变。 这意味着我们可以将任何矢量存储在该象限中作为颜色,因为每个矢量都有唯一的颜色。
但是其他三个象限存在问题。 我们沿一个轴只有一个梯度,或者根本没有梯度。 这意味着几个矢量将具有相同的颜色。 例如,我们无法区分向量
(-1,1)和
(0,1) 。
这三个象限的每个矢量没有唯一的颜色,因为我们只能使用0到1的值表示颜色。但是,这三个象限使用此范围之外的负值。
解决方案是重新分配向量,以使它们都适合从0到1的间隔。这可以通过将向量乘以
0.5并加上
0.5来完成 。 这是我们得到的可视化效果:
现在,每个向量都有唯一的颜色。 当需要将其用于计算时,我们只需将其重新分配回-1到1的间隔即可。以下是几种颜色,以及重新分配后的相应方向:
- (0,0):负的X和Y
- (0.5、0.5):无动作
- (0,1):负X和正Y
- (1,0):正X和负Y
现在让我们学习如何在虚幻引擎中创建矢量场。
创建矢量场
与在雪中创建痕迹不同,我们将不执行对象形状的捕获。 相反,我们将使用画笔在渲染目标上进行绘制。 这些将只是所选矢量场的图像。 我称它们为
方向刷 。
除了使用钝器在渲染目标上绘制外,我们还可以使用
粒子 。 粒子将显示方向笔刷并从播放器发出。 要创建矢量场,我们只需要使用场景捕获并仅捕获粒子即可。 这种方法的优点是创建跟踪非常简单。 另外,它使您可以轻松管理属性,例如轨道的存储时间及其大小。 此外,粒子会创建临时的持久性痕迹,因为它们在离开捕获区域并返回到捕获区域之后才存在。
以下是一些我们可以使用的定向画笔的示例,以及它们对草的影响。 请注意,在下面的示例中,粒子是不可见的。
首先,让我们创建一个显示方向笔刷的材质。
创建指导材料
有两种创建方向笔刷的方法:
- 数学:方向和形式设置在材料内部。 它的优点是它不需要第三方软件,并且对于简单的表单很方便。
- 法线贴图转换:创建所需方向和形状的法线贴图。 要将地图转换为合适的矢量场,我们只需删除蓝色通道即可。 这种方法的优点是您可以轻松地创建复杂的形状。 下面是一个很难在数学上创建的画笔示例。
在本教程中,我们将在数学上创建画笔。 转到“
材料”文件夹并打开
M_Direction 。 请注意,为此材质选择了阴影模型“不
发光” 。 这很重要,因为它允许捕获场景以捕获粒子而不影响它们。
为了不复杂,我们将创建一种材质,该材质将导致草从粒子中心移开。 为此,请创建以下方案:
现在我们需要重新分配。 为此,添加选定的节点并按如下所示连接所有内容:
现在,让画笔呈圆形。 为此,添加选定的节点:
RadialGradientExponential控制圆圆周的大小和清晰度。 将其乘以“
粒子颜色”可以使您控制粒子系统中粒子的不透明度。 我将在下一部分中对此进行详细讨论。
这是刷子的样子:
单击“
应用”,然后关闭材料。 现在我们已经创建了材料,现在该着手构建一个粒子痕迹系统了。
创建粒子跟踪系统
转到
ParticleSystems文件夹并打开
PS_GrassTrail 。 为了节省时间,我已经创建了所有必需的模块。
以下是每个模块如何影响草足迹的方法:
- 生成:创建频率会影响轨道的平滑度。 如果轨道看起来是断断续续的,那么您应该增加创建的频率。 在本教程中,我们将保留默认值(20)。
- 生命周期:直到草地恢复其原始状态的路径的生命周期
- 初始大小:迹线大小
- 使用寿命内的颜色:由于我们在材质中使用了“粒子颜色”,因此您可以在此处控制不透明度。 您还可以更改Alpha曲线以控制音轨的消失。 例如,您可以选择线性消失,缓和和/或缓和。 在本教程中,我们将保留默认设置,即线性损耗。
- 锁定轴:用于将粒子引向场景捕获
- 初始旋转:用于确保粒子沿正确的轴定向(更多信息,请参见下文)
首先,我们需要设置材料。 选择“
必需”模块,并将“
材质”设置为
M_Direction 。
还将“ 排序模式”设置为“
PSORTMODE年龄最短” 。
此排序模式使您可以在旧粒子上渲染新粒子。 如果不这样做,则不是新的,而是旧的粒子会影响草。
接下来是跟踪的持续时间。 选择
Lifetime模块,并将
Constant设置为
5 。 因此,跟踪将在五秒钟内消失。
现在,让我们继续走线的大小。 选择
初始大小模块,并将
常量设置为
(150,150,0) 。 因此,每个粒子将覆盖150×150的面积。
现在我们需要使其朝捕获场景的方向看。 由于场景是从上方捕获的,因此粒子应朝Z轴正方向看,为此,请选择“
锁定轴”模块并将“
锁定轴标志”设置为
Z。最后,我们需要设置粒子的旋转。 当前,画笔颜色与它们表示的方向不对齐。 发生这种情况是因为默认情况下,将粒子系统旋转90度。 要解决此问题,请选择“
初始旋转”模块,并将“
常量”值设置为
-0.25 。 这会将粒子逆时针旋转90度。
这就是粒子系统所需要的,所以让我们关闭它。
接下来,我们需要将粒子系统附加到应该创建轨迹的对象上。 就我们而言,我们需要将其附加到玩家的角色上。
附着粒子系统
转到“
角色\模特”,然后打开
BP_Mannequin 。 接下来,创建
Partice System组件并将其命名为
GrassParticles 。
接下来,我们需要定义一个粒子系统。 转到“详细信息”面板,然后将“
粒子\模板”设置为
PS_GrassTrail 。
如果玩家可以看到游戏中的轨迹,那将很奇怪,因此值得将其隐藏。 为此,请启用“
渲染\所有者看不见” 。
由于粒子系统已附加到播放器(所有者)上,因此播放器将看不到它,但其他所有对象均可见。
单击“
编译” ,然后单击“
播放” 。 请注意,粒子不会出现在播放器的相机上,而是显示在渲染目标上。
到目前为止,场景捕获已设置为捕获
所有内容 。 显然,这不适合我们,因为只有粒子会影响草。 在下一节中,我们将学习如何仅捕获粒子。
粒子捕捉
如果现在捕获粒子,我们将在没有粒子的区域执行不必要的弯曲。 这是因为渲染目标的背景色是黑色。 发生弯曲是因为黑色表示向负XY轴移动(重新分配之后)。 为了使空白区域不包含运动,我们需要使背景目标渲染
(0.5,0.5,0) 。 最简单的方法是创建一个巨大的平面并将其附加到播放器上。
首先,为背景创建材料。 返回到内容浏览器并打开
Materials \ M_Background 。 然后将常数
( 0.5,0.5,0 )与
发射颜色相连。
注意:与粒子材质一样,我们捕获的任何材质都必须具有未照明的着色器模型。
单击“
应用”,然后关闭材料。 返回到
BP_Mannequin ,然后创建一个新的
Plane组件。 将其命名为
Background 。
接下来,设置以下属性:
- 位置: (0,0,-5000)。 我们将平面放置得太低,使其不与任何粒子重叠。
- 比例尺: (100,100,1)。 因此,我们缩放到足以覆盖整个捕获区域的大小。
- 材质: M_背景
与粒子一样,如果玩家看到下面有一个巨大的黄色飞机,那将很奇怪。 若要隐藏它,请启用“
渲染\所有者看不见” 。
现在我们已经设置了背景,是时候捕获粒子了。 我们可以通过将粒子系统添加到场景捕获
的仅显示列表中来做到这一点。 这是将捕获场景捕获的组件列表。
使用仅显示列表
在我们可以将其添加到仅显示列表之前,我们需要一种方法来获取所有影响草的参与者。 获得它们的一种方法是使用
标签 。 标签是可以分配给参与者和组件的简单字符串。 然后,您可以使用“
使用标签获取所有演员”节点来获取所有具有相应标签的演员。
由于玩家的演员必须影响草地,因此他需要标签。 要添加标签,请单击“
Class Defaults”按钮。 然后在
Actor \ Tags中创建一个新标签,并将其命名为
GrassAffector 。
由于只能将
组件转移到仅显示列表,因此我们需要向影响草的
组件添加标签。 选择
GrassParticles组件,然后在“
标签”部分添加一个新标签。 也将其命名为
GrassAffector (
不必使用此标签)。 对
Background组件重复相同的操作。
现在,我们需要将影响草的组件添加到场景捕获的仅显示列表中。 单击
编译,然后关闭
BP_Mannequin 。 然后打开
Blueprints \ BP_Capture 。 转到
事件BeginPlay并添加突出显示的节点。 还要确保已连接标记的引脚。
该电路将循环所有具有
GrassAffector标签的参与者。 之后,她将检查演员是否具有带有此标签的组件,并将其添加到仅显示列表中。
接下来,我们需要告诉场景捕获仅使用仅显示列表。 选择
SceneCapture组件,然后转到“
场景捕获”部分。 将
原始渲染模式设置为
使用ShowOnly列表 。
单击
编译,然后关闭蓝图。 如果单击“
播放” ,您将看到渲染目标现在仅捕获粒子和背景平面。
在下一节中,我们将达到预期的效果。 是时候教草弯曲了!
弯曲草
首先,我们需要在草地上投影渲染目标。 转到“
材料”文件夹并打开
M_Grass 。 然后创建如下所示的节点。 将纹理设置为
RT_Capture 。
由于我们以0到1的间隔重新分配颜色,在使用它们之前,我们需要以-1到1的间隔重新分配颜色。为此,请添加突出显示的节点:
现在我们有了弯曲方向,我们需要一些方法来沿该方向旋转草。 幸运的是,有一个名为
RotateAboutAxis的节点。 让我们来创建它。
让我们从
NormalizedRotationAxis接触开始。 顾名思义,这是顶点将绕其旋转的轴。 要进行计算,我们只需要弯曲方向为
(0,0,-1)的
向量积即可 。 为此,我们需要添加选定的节点:
我们还需要指定
RotationAngle ,即顶点相对于旋转点的旋转量。 默认情况下,该值应介于0和1之间,其中0为0度,而1为360度。 要获得旋转角度,我们可以使用弯曲方向的长度乘以最大旋转。
乘以最大旋转
0.2将意味着最大旋转角度为
72度。
计算
PivotPoint有点困难,因为单个草网包含多个茎。 这意味着我们不能使用“
对象位置”节点之类的东西,因为它将为所有草茎返回单个点。
理想情况下,您应该使用第三方3D编辑器将枢轴点保存在UV通道内。 但是对于本教程,我们只是近似枢轴点。 这可以通过从上
向下移动到某个偏移量来完成。
为此,添加选定的节点:
在本教程中,草高约
80个单位,因此我为
PivotOffset设置了该值。
接下来,我们需要执行两个遮罩。 第一个面具确保茎的根部不会移动。 第二个遮罩可确保没有矢量场作用在捕获区域外的草地上。
遮罩
在本教程中,我设置草顶部的颜色,以使底部顶点为黑色,顶部顶点为白色。
要掩盖根,我们只需将
RotateAboutAxis的结果乘以“
顶点颜色”节点即可。
为了遮盖捕获区域之外的草,我们将先前的结果乘以选定的节点:
单击“
应用”,然后关闭材料。 单击“
播放”并在草地上奔跑,在上面留下足迹!
接下来要去哪里?
可以
从此处下载完成的项目。
尽管本教程中显示的方法对于诸如草之类的简单对象非常有效,但在使用需要更多动态性的对象时还远远不够。 该问题的部分解决方案是使用叶子的物理版本。 有关更多信息,请参见
这篇关于交互式叶子的
文章 。
最后,我要感谢虚幻引擎社区的Deathrey提供了这种粒子方法的技巧!