在Niagara中创建粒子效果
介绍
我叫阿列克谢。我已经在 Allods Team (My.Games) 担任高级 VFX 美工八年了,尽管我已经获得了编程学位。然而,有时,仅凭动机就足以帮助您走上您选择的道路。我参与过 Skyforge、Armored Warfare、Warface Mobile 等项目,并帮助我们公司的其他团队完成各种项目。现在,我正在为 PC 和控制台开发一个新的雄心勃勃的虚幻引擎项目。
在我们国家,Allods Team 工作室是一个非常传奇的团队,加入他们是梦想成真。我从一名初级 VFX 艺术家开始,我的前辈帮助我发展了大部分基本工作技能并了解了我的工作。
现在,我负责效果创建的整个周期:从与设计师一起提出视觉效果到创建纹理、模型、着色器,在 Niagara 中构建效果,消除错误,并在将它们纳入项目后支持它们. 作为一名 VFX 艺术家,我还负责后期处理材料、环境和角色材料的各种效果。团队合作是关键!
处理粒子效果
大约九年前,当我还是一个小工作室的游戏设计师/通才时,我开始研究粒子效果。我真的被这份工作的艺术方面所吸引,知道如何绘画和建模。所以,我得到了为类似 MOBA 的游戏制作效果的提议。我们使用 BigWorld 引擎并在记事本中直接以 XML 格式构建所有效果。这一切都非常有趣,我很快就将自己训练成一名 VFX 艺术家。那时,我不知道视觉效果的世界如此深刻和复杂。后来,我不得不学习很多当时一无所知的各种重要事情。
当谈到可供任何工作室使用的开放引擎时,市场上只剩下两个主要参与者,这已不是什么秘密。虚幻引擎和 Unity。虚幻引擎最初面向大型项目,其粒子引擎和材质编辑器非常适合任何美术师的需求,不需要程序员的帮助。易于学习且功能强大。但 Unity 一直以来都在喘气。它从未停止前进,其开发人员定期添加新工具。我认为比赛对每个人都有帮助。但自从 Niagara 为 UE 4 推出后,虚幻引擎设法大幅拉大了差距。
UE4中的尼亚加拉
Niagara 测试模式一发布,我就拿起了它。使用如此深刻的东西是一次难忘和鼓舞人心的经历。一句话,不可思议。
Niagara 的工作方式与其他游戏引擎和 3D 套件的大多数粒子系统类似。您创建了一个由产生粒子的发射器组成的效果(Niagara System)。在发射器内部,有一组用于调整粒子的选项,以及用于添加可让您控制粒子行为的修改器(模块)的选项。有很多这样的模块,它们几乎可以满足 VFX 艺术家的任何需求。但更重要的是,您可以自己创建模块,为它们分配您需要的逻辑。这是 Niagara 最令人难以置信和令人兴奋的功能之一。
简单案例
一开始,功能的数量可能看起来相当令人印象深刻且难以掌握。但实际上,该工具包非常直观且易于理解。它与其他类似的编辑器非常相似。您还可以找到许多方便的工具来帮助您掌握模拟。例如,编辑器本身包含已经配置了主要模拟类型的发射器模板,您可以看到它们是如何构建的。Epic Games Store 中还有内容示例,其中包含示例效果,您可以使用它们来提出新的想法和解决方案。Youtube 有无数的教程视频。还有一个名为“Unreal Slackers”的 Discord 服务器,您可以随时寻求帮助。
复杂案例
Niagara 有趣的特性之一是它的灵活性。您几乎可以做(或尝试做)任何事情,即使这不是 Niagara 最初设计的目的。您只需单击两次即可查看任何模块的工作情况。您可以更改已经存在的模块并扩展或修改它们的功能。当然,您可以创建自己的模块。
下面我将分享一些每个 VFX 艺术家最终可能会遇到的例子。也许,它会证明对某些读者有用。
示例一
例如,我们可能需要将精灵放置在一个圆圈中,光线来自中心。我们还希望它适用于任意数量的粒子。
如下图所示。
![](https://cdn.80.lv/api/upload/content/2b/6075251e4a760.gif)
首先,我们将每个粒子的旋转放在根据它们的数量归一化的曲线上。
![](https://cdn.80.lv/api/upload/content/96/images/6075252ad3cfa/widen_920x0.jpg)
然而,在我们的例子中,我们最终看到的粒子比我们指定的少一个。对于 2 个粒子,我们只会看到 1 个,对于 5 个,我们只会看到 4 个。这是因为第一个和最后一个粒子组合在一起,因为它们具有相同的旋转角度。
![](https://cdn.80.lv/api/upload/content/13/6075259e075f2.gif)
为了解决这个问题,我们需要根据实际产生的粒子数量对曲线进行归一化,但要添加一个额外的粒子。为此,我们可以编写一个简单的脚本(Niagara 动态输入脚本)。我将称之为 NSC_ReturnNormalizedIndexPlus1。
![](https://cdn.80.lv/api/upload/content/26/images/607525ed05236/widen_920x0.jpg)
让我们把它放在我们的曲线索引中,而不是返回标准化执行索引。
我们也可以使用 Scratch Dynamic Input 做同样的事情,它非常有用,因为它让我们可以在资产内部工作。
![](https://cdn.80.lv/api/upload/content/1c/images/6075297882131/widen_920x0.jpg)
但是由于我们将来可能会遇到同样的问题,因此创建一个外部脚本并根据需要使用它会更容易。
之后,我们可以生成任意数量的粒子,它们都会正确显示。
![](https://cdn.80.lv/api/upload/content/4d/607529cbf089b.gif)
如果我们需要在空间中定位粒子,无论是精灵还是几何体,我们的脚本也能很好地工作。
我们将在精灵的对齐和将精灵对齐网格方向模块中使用自定义对齐而不是旋转。对于几何体,我们需要初始网格方向。我们还将使用归一化曲线来确定每个粒子的方向。我们需要使用来自曲线的矢量而不是矢量,并使用曲线设置粒子方向。
![](https://cdn.80.lv/api/upload/content/47/images/607529cdc8545/widen_920x0.jpg)
这样我们就可以在 System Location 模块中设置位置。
这是我们的粒子:
![](https://cdn.80.lv/api/upload/content/b3/607529ec779ee.gif)
示例二
让我们转向更困难的事情。
例如,我们可能想要一些粒子,例如魔法火花,围绕手或可以随机轨迹移动的东西飞行。为此,我们可以将其拉到随机出现在手周围的其他发射器的粒子上。
让我们创建这样一个发射器并将其命名为 Attractor。它必须放置在局部空间中,以便我们的吸引力点始终围绕手。
![](https://cdn.80.lv/api/upload/content/61/images/60752abe64315/widen_920x0.jpg)
您将在粒子生成部分中找到该发射器粒子的所有属性。
我们将使用 SpawnRate 2 和 Lifetime 0,5 生成粒子。对于更动态的火花运动,我们可以相应地增加 SpawnRate 并减少 Lifetime。
![](https://cdn.80.lv/api/upload/content/1b/images/60752ade55a04/widen_920x0.jpg)
我们将在一个小球体的边缘产生粒子,这样它们就会被分散开,火花就能在它们之间的空间中飞舞。
![](https://cdn.80.lv/api/upload/content/b8/images/60752af5dd5ee/widen_920x0.jpg)
我们还可以继续将效果附加到角色的 SkeletalMesh 上,以查看我们的效果是否有效。为此,我们需要在发射器中添加 SkeletalMeshLocation 模块。让我们也立即设置位置,以便粒子在右手指针和无名指的骨骼之间生成。
![](https://cdn.80.lv/api/upload/content/99/images/60752b454432b/widen_920x0.jpg)
要工作,SphereLocation 需要设置为低于 SkeletalMeshLocation。
您还可以添加 CameraOffset 以查看粒子,即使它们沉入手中。
![](https://cdn.80.lv/api/upload/content/e9/60752b6e24812.gif)
这些粒子会吸引我们的主要魔法火花粒子。
让我们为我们的火花创建一个发射器,并将其命名为 Core。它也必须设置在本地空间中。
接下来,让我们使用 SpawnBurstInstantaneous 生成单个粒子并使其“不朽”。
![](https://cdn.80.lv/api/upload/content/e9/images/60752b749270b/widen_920x0.jpg)
为了确保它在开始时正确定位,我们将像之前的发射器一样在右手中生成它。
为了将我们的火花吸引到 Attractor 发射器的粒子上,我们需要将它们的位置发送到 PointAttractionForce 模块。为此,让我们创建 Niagara 模块脚本,它将接收指定发射器粒子的属性。我们称之为 NSC_GetPositionAttribute。
![](https://cdn.80.lv/api/upload/content/c3/images/60752b919e4ee/widen_920x0.jpg)
此脚本从发射器扫描粒子位置并将其写入 SoughtPosition 变量。当我们将此脚本添加到我们的发射器时,该变量将出现在变量列表中,我们将能够在其他模块中使用它。添加我们的脚本后,将 Attractor 放在 Emitter Name 字段中。然后添加 Point Attraction Force 模块并将我们的新变量设置为 Attractor Position 中的 SoughtPosition。我们还应该限制我们的火花的速度,以防止它飞离我们的吸引力点太远。
![](https://cdn.80.lv/api/upload/content/bc/images/60752bdcd70c5/widen_920x0.jpg)
您可以调整火花的颜色并将光源添加到同一个发射器。要隐藏我们的吸引力点,您需要将它们的颜色设置为 A = 0。
![](https://cdn.80.lv/api/upload/content/34/60752c1ead3c0.gif)
我们的火花在手周围飞舞,即使我们的角色移动,它也会留在那里。现在,由于我们的火花是神奇的,我们可能想在它的尾迹中添加一些小粒子或添加一条丝带轨迹。如果我们的手一动不动,我们可以只使用本地发射器来跟踪。我们可以使用我们的 NSC_GetPositionAttribute 脚本并在 System Location 中标记 SoughtPosition。但是如果我们希望我们的轨迹即使在移动时也能保持原地不动,我们需要轨迹发射器的世界坐标。由于火花坐标是局部的(必须使火花跟随手),我们不能直接得到它的世界坐标。
让我们编写几个新脚本。第一个将形成世界坐标,第二个将接收它们。
首先,让我们创建一个 Niagara 模块脚本并调用它 NSC_SetWorldPositionAttribute 来形成世界坐标。最初,我们的粒子具有相对于它们的发射器的局部坐标和方向。这意味着我们需要给他们系统的世界坐标并记住它的方向。让我们将得到的坐标写入一个新变量——WorldPosition。
![](https://cdn.80.lv/api/upload/content/a4/images/60752c4be5c64/widen_920x0.jpg)
读取世界坐标属性的脚本与获取普通粒子坐标的脚本类似。我们称之为 NSC_GetWorldPositionAttribute。
![](https://cdn.80.lv/api/upload/content/82/images/60752c6253212/widen_920x0.jpg)
接下来,让我们将 NSC_SetWorldPositionAttribute 模块添加到粒子更新部分的 Core 发射器中。
我们现在可以获取路径所需的世界坐标。为此,我们需要将 NSC_GetWorldPositionAttribute 模块添加到尾迹发射器的粒子生成部分。如果我们想使用像 Location 这样的模块,它们需要在我们的脚本下面设置。
结果,我们得到了一个带有本地坐标的火花的工作效果,它产生了一个带有世界坐标的轨迹。
例三
最后,我把最好的留在了最后。
我们可能希望能够围绕轴旋转粒子并根据运动定位它们。这可能有很多用途,例如,在旋风或一些神奇的漩涡中旋转石头和碎片。我们可以尝试使用标准的 Vortex Force 模块,但由于其离心力,粒子会简单地散射。所以,我们需要一些更易于管理的东西。让我们从旋转轴固定在 Z 的最简单情况开始。
解释可能有点难理解,但我尽量把它说清楚。
首先,我们需要创建两个脚本。第一个 NSC_InitialCylindricalMove 将初始化基础值,而第二个 NSC_UpdateCylindricalMove 将为我们的粒子设置动画。为了使调试更容易,我们还将在 Scratch Pad 中创建模块,并在最后将它们转换为资产。
![](https://cdn.80.lv/api/upload/content/00/images/60752cbfd7617/widen_920x0.jpg)
我们的粒子做圆周运动,所以为了描述它的运动,我们需要一个半径和旋转速度。现在,将它们设置在第一个模块中并将它们变成变量。为确保这些变量保持唯一,请为每个名称添加一个 Cylinder 前缀。
![](https://cdn.80.lv/api/upload/content/70/images/60752cf24b901/widen_920x0.jpg)
在第二个脚本中,我们将描述圆周运动。
![](https://cdn.80.lv/api/upload/content/e0/images/60752d1161be8/widen_920x0.jpg)
不要忘记按应用,以便对脚本的更改生效。如果初始化模块中的值没有设置为零,我们已经可以看到我们的粒子在做圆周运动。
![](https://cdn.80.lv/api/upload/content/07/images/60752d299a4c5/widen_920x0.jpg)
![](https://cdn.80.lv/api/upload/content/6c/60752d326913d.gif)
粒子一直从同一个点开始,所以让我们添加一个选项来设置圆上的位置和高度。
第一个脚本:
![](https://cdn.80.lv/api/upload/content/ca/images/60752d5302aaf/widen_920x0.jpg)
第二:
![](https://cdn.80.lv/api/upload/content/ae/images/60752d6a235b8/widen_920x0.jpg)
现在我们可以通过设置半径、径向位置和高度来移动圆柱体内的粒子。
![](https://cdn.80.lv/api/upload/content/86/images/60752d7a8ad37/widen_920x0.jpg)
![](https://cdn.80.lv/api/upload/content/3d/60752d8ad9a3f.gif)
接下来,我们需要添加运动方向。为此,让我们将所有计算后得到的粒子位置减去计算前的位置。结果是一个刻度的矢量距离或速度矢量。然而,在第一个刻度中,之前的位置还没有被计算出来并被设置为 0,这意味着我们第一个刻度的距离向量将是不正确的。你可以检查一下,当之前的位置为 0 时,我们将根据计算后的位置和我们圆柱轴的向量之间的叉积来设置方向。即 (0,0,1)。这不是最好的向量,但至少这样我们可以避免第一个刻度中的向量距离故障。
![](https://cdn.80.lv/api/upload/content/42/images/60752dbee9307/widen_920x0.jpg)
现在,我们需要做的就是在 Sprite Renderer 部分中将粒子方向设置为 Custom Alignment,并且我们的精灵应该根据它们的运动向量进行定向。
![](https://cdn.80.lv/api/upload/content/65/60752ddc1a086.gif)
为了完成脚本,让我们为网格添加方向。在第一个脚本中,初始化 CylinderMeshOrientation 变量,这将帮助我们在已经计算出速度矢量时设置方向。
![](https://cdn.80.lv/api/upload/content/da/images/60752e0f5f34a/widen_920x0.jpg)
![](https://cdn.80.lv/api/upload/content/cb/images/60752e222fb92/widen_920x0.jpg)
检查一切是否正常。
![](https://cdn.80.lv/api/upload/content/3a/60752e3acf045.gif)
现在,我们终于可以将 Scratch Pad 中的脚本转化为资产并充分利用它们。当然,可以扩展脚本。您可以添加偏移位置、更改轴方向、动画半径和高度等。您可以轻松添加这些功能,因为 Niagara 脚本非常通用
我迫不及待地想看到用 Niagara 制作的新酷脚本和效果!