带你在 visionOS 上玩转粒子
掘金、知乎题头
XR 基地是一个专注于 XR 领域的创作者社区,我们的目标是 让 XR 开发变得更简单!
写在最前面
你是否有想象过,在未来混合现实的空间中,虽然坐在自己房间的椅子上,却感受着漫天飞舞的樱花,或经历着一场暴风雨中的海盗大战,或在漫漫风沙扬起的戈壁滩上寻找传说的宝藏?这些场景中飞舞的樱花、纸片、落叶,或飘扬的雨点、雪花、柳絮以及绚丽的烟花、魔法光束大部分都可以由粒子(Particles)构成。
在无尽想象的空间计算时代里,粒子效果给我们带来的不仅是更逼真的场景体验,也是未来 3D 交互中与现在 2D 交互中动画一样重要的界面元素之一。在 RealityKit 中曾经一直缺位的粒子系统,伴随着 Apple Vision Pro 的发布一同到来。目前有两种方式可以直接构建基础原生的粒子效果:
- 通过 Reality Composer Pro 进行构建。方法是在一个任意的 Entity 上增加一个 Particle Emitter Component;
- 直接在代码里构建添加。方法是在
ImmersiveView
里为一个ModelEntity
添加一个ParticleEmitterComponent
的 component。
下面我们将会带着大家一起了解 visionOS 上粒子的基本用法以及一些注意事项。这篇文档总结、参考了社区中方方面面的资料,在此,特别感谢 Yasuhito Nagotomo 帮忙审核文章!
这篇文章力求可以让从小白到在其它软件中(比如 Unity, Unreal,Blender 等)使用过粒子的大佬都能有所收获,所以对于一些第一次出现的词语我们会进行解释并附上对应的英文名词,对于一些高阶使用提示我们会用💡表示。另外,斜体表示对应 Reality Composer Pro 中的按钮名词,所有英文的翻译由机器翻译配合人工校对,如果有错误欢迎指出。
粒子的基本概念
与其他软件的对比
虚幻引擎中的粒子系统(Cascade 和 Niagara):
- Cascade:这是虚幻引擎中老版本的粒子系统。 它允许用户主要通过其基于节点的模块化系统创建和修改视觉效果。
- Niagara:这是虚幻引擎中更先进的粒子系统。 Niagara 比 Cascade 提供了更大的灵活性,允许粒子之间进行更复杂的相互作用,甚至与环境中的其他元素进行相互作用。
- 系统特点:
- 使用 GPU 驱动:对大量粒子进行高效模拟。
- 可定制化高:允许对粒子行为进行复杂的定制。
- 与其他虚幻引擎中的系统(例如音频、灯光)集成。
Unity 中的粒子系统(Shuriken 和 Visual Effect Graph):
Unity 中也有两套粒子系统:
- Shuriken:Unity 中老版本的粒子系统。 它提供了一种基于组件的方法,用户可以使用一系列模块创建和修改粒子效果。
- Visual Effect Graph (VEG):Unity 中新的粒子系统,专为高性能视觉效果而设计。 它使用类似于 Shader Graph 的节点系统。
- 特征:
- 使用 GPU 驱动:专为大规模效果而设计。
- 灵活的基于节点的系统:允许复杂的自定义效果。
- 与其他 Unity 系统集成,可以通过脚本进行控制。
Blender 中的粒子系统(Particles 和 Mantaflow):
同样,Blender 中也有两套粒子系统:
- Particles:Blender 的传统粒子系统。 它可以处理各种任务,包括头发、毛皮和基本模拟。
- Mantaflow:Blender 中的集成模拟框架,用于创建更复杂的效果,如烟雾、火焰和液体。
- 特征:
- 多功能性:除了视觉效果之外,它还用于头发和实例化几何体。
- 基于物理的模拟:可以与 Blender 的物理系统配合使用。
- 与 Blender 的其余部分紧密集成:这使得它适用于 VFX 之外的一系列任务。
总结来说,Unreal 引擎以其高质量的电影功能而闻名,而 Niagara 则提高了引擎内实时视觉效果的标准。而 Unity 一直在快速发展,凭借 Visual Effect Graph,为高端视觉效果提供了具有竞争力的解决方案,特别是针对 Unity 已经嵌入其业务领域的用户。 Blender 虽然主要是一款 3D 建模和动画软件,但也提供了强大的粒子系统。 它可能不如游戏引擎那样实时高效,但为预渲染视觉效果提供了全面的解决方案。那么随着 Apple Vision Pro 发布一同到来的 Apple 原生的粒子系统有哪些特性呢,让我们一起来看看。
创建基础粒子效果
想要创建一个粒子效果我们首先必须有一个 Entity,让我们首先打开 Reality Composer Pro(以下简称 RCP),这里我们创建一个立方体举例。创建之后在右下方的 Add Component 里我们能找到 Particle Emitter 的选项,点击添加之后我们就得到一个默认发射方向朝上(Y 轴正方向)的粒子效果。
发射器(Emitter):用于发射粒子,通过配置参数改变粒子效果。
对应的,在 RCP 的右侧有发射器属性调节的面板,也有对粒子属性进行调节的面板,下面我们就会穿插着进行说明。首先发射器一次发射多少粒子由 Particels 中 Birth Rate 控制,为了增强粒子的随机性,对应的有 Variation 对 Birth Rate 进行一些随机的增减。Burst Count 是指一次全体发射的粒子数量,有对应的随机化参数 Variation,当然我们可以在粒子播放期间通过点击 burst 来测试一次全体发射的效果。
除此之外,我们还需要了解的一个基本属性就是时间。是否是循环发射,发射一次持续多长时间,以及发射前等待的时间则由 Emitter 中的 Timing 子模块控制。其中 Emission Duration 控制一次发射时长,单位为秒。Idle Duration 控制两次发射之间的间隔时间,单位为秒。这两个属性都有随机变化的 Variation 选项,但是随机增 / 减不会让时间减少到负数 。另外 Warmup Duration 控制在首次发射之前,第一帧应该出现多长时间。以上效果演示如下:
其中参数 Spreading Angle 是决定整体粒子的散开角度,单位为弧度。这是发射器的属性,在 particle 的 main emitter 中进行调节。除此之外,基础粒子效果还有几个预设的基本属性,比如 Color 决定了粒子的颜色,有单色和渐变色两种选择,默认是从橙到蓝的渐变色。
另外,Size 控制粒子图像的渲染大小(以场景的世界坐标空间为单位),默认值为 0.02,单位是米。对应的,我们也可以直接在 Xcode 里创建这样一个初始的粒子:
其中是否循环发射不再类似 RCP 中的 Looping 进行控制,而是 particles.timing
的值进行控制,执行一次和循环的区别如下:
自定义粒子效果
大家肯定不会满足于使用基础粒子效果,所以接下来我们将会对基础粒子效果进行更深入的自定义。首先我们需要了解是什么决定了粒子效果区域的大小。粒子发射器所依附的 ModelEntity 有一个默认的形状,我们称之为原始形状。对应的,附着的粒子发射器也有一个默认形状,可以和 ModelEntity 的形状相同也可以不同:
原始形状(Shape Primitive):决定 ModelEntity 的原始形状大小。
原始粒子效果区域形状(Particle Primitive): 决定粒子发射器初始范围以及发射形状
这个原始形状的大小一般和原始粒子效果区域形状大小一致,它决定了整个粒子效果的区域形状大小的初始值。不同的形状有不同的原始大小:
- 点(Point): 球,1 厘米
- 立方盒子(Box):立方体,20 厘米
- 平面(Plane):正方形,20 厘米
- 圆锥体(Cone):高 20 厘米,底面半径 10 厘米
- 球体(Sphere):半径 15 厘米
- 圆柱体(Cylinder):高 20 厘米,底面半径 10 厘米
- 环形(Torus):外半径 10 厘米:内半径 15 厘米
当我们修改原始形状(如下图展示的是 Cube Primitive )大小的的时候,粒子效果区域形状大小不会被改变,想要单独修改粒子效果区域形状大小需要通过属性 Emitter Shape Size。当我们勾选了 Particle Inherit Transform 参数,则通过在 Transformer 里面的 Scale 对整个 ModelEntity 进行修改时则会同时修改形状大小和粒子形状大小。具体关系如下图所示。
当然我们也可以看到,默认有 7 种粒子效果区域形状可以通过 Emitter Shape 进行修改,如下图所示。
而通过 Emitter Direction 可以修改发射的方向,默认方向和选择的形状相关,注意因为这个参数只是决定朝向,当单独沿着轴方向时,值的大小并不会影响方向。同时需要注意的是,如果希望 Emitter Direction 可以生效需要设置合适的 Birth Direction。具体来说如果选择法向(normal)的话,则 Emitter Direction 参数失效,如下图所示。
💡 当想要判断发射器的形状时候,以及在测试一些粒子的效果时候,我们建议使用 速度控制参数 Speed,通过把发射速度设置到足够小,我们可以相对静止的看到粒子的形状。(同时粒子的 Birth Rate 要足够大才能看起来相对静止)
以上所有的粒子发射点都是在表面。类似 Blender,我们还可以修改 Birth Location 来选择从 ModelEntity 内部生成;或从顶点生成。
粒子发射点(Birth Location):粒子初始产生的位置
这其中顶点生成相比其它几个方式比较复杂,它并不是简单的从形状的顶点生成,而是由所选取的形状参数以及每个方向上的顶点数量参数联合决定,我们的建议是,在粒子效果设计的时候,我们可以通过从一个轴出发进行再逐渐扩展到另外两个轴。或者就通过多尝试,实践出真知。另外当我们选择球面、圆柱、圆锥形发射器或环形的时候,我们会有一个额外的 Radial Amount 或 Torus Inner Radius 参数可以控制扫射角度或半径。
利用代码在 Xcode 里实现上述效果也非常简单,只需要注意一些成员变量和 RCP 里的 GUI 的名称不太一致,一些变量的单位需要换算即可(Xcode 里面大部分单位是米,而 RCP 里面是厘米)。
深入粒子发射器
看到这里,请给自己鼓一个掌!你已经了解了大部分粒子配置的参数,在我们举一些具体粒子效果的例子之前,让我们完成剩下的一点点知识点的学习。我们将会继续讨论发射器里面一些更细节的参数,以及我们在 XR 世界导览 NEWSLETTER #010 里面说到,目前的粒子系统最多支持关联两个发射器,一个是 mainEmitter 另一个是 secondaryEmitter。特别是使用到 secondaryEmitter 的时候情况则变的更复杂一些,比如两个发射器之间怎么切换衔接,别着急我们一步步来。
虽然使用两个发射器听起来很复杂,但是只要搞清楚一个发射器的配置,另一个发射器则只需要作出一些改变即可。我们在基础粒子效果的时候讨论了粒子颜色的参数,现在我们可以对其进行更为复杂的设置,比如我们可以通过 Color Evolution Power 设置渐变颜色的变化速度,而 Opacity Over Life Mode 则可以对粒子的发射以及消失进行一些动画设置,比如我们常见的 easeFadeIn
等。
除了颜色以外,我们还可以自定义粒子的外观(在 RCP 里也被称为材质)。官方给的粒子样例使用的是 .exr
这种 HDR 的图像格式,我们也可以使用 PNG 图像。除了单一的材质图像(比如下图中的叶子),我们也可以在一张图里放多个粒子状态(可以是行列数一致的排列或不一致的排列),之后设置成 is Animated 并通过 Row Count 和 Column Count 指定材质图像的排列就可以按照顺序进行粒子材质的渲染了。当然我们也可以只选择部分材质序列进行渲染,比如下面的 6 个颜色的心,我们可以通过 Initial Frame 和 Frame Rate 来控制是否从红色心形开始渲染,以及往后渲染几个不同颜色的心形。
同时多行多列的粒子材质渲染也可以通过参数 Animation Mode 来配置是否是循环显示,或者往复循环,也可以只播放一次。
需要注意的是, RCP 里的材质解析和 Unity 等引擎的不太一样,直接使用 PNG 图像会导致颜色解析错误以及白边现象。
导致出现问题的原因是 Apple 使用了另一种渲染模式(感谢 Yasuhito Nagotomo 和 WenBo):
- 预处理 Alpha 渲染模式(Premultiplied Alpha):将图像中的 RGB 值乘以 Alpha 值。 在不考虑 Alpha 通道的情况下查看时,此类图像可能看起来比预期更暗,因为 RGB 值已乘以 Alpha(如下图第一行所示);
- 举例:如果原 RGB 颜色为 (R, G, B) 且 alpha 值为 A(范围从 0 到 1),则目标存储的值将为 (R*A, G*A, B*A, A);
- 使用原因:由于混合和合成结果更清晰,通常在电影和视频制作中首选;
- 缺点:后期制作中如果改变 Alpha 值则可能无法恢复图像原始颜色;
- 非预处理 Alpha 渲染模式(Non-premultiplied Alpha or Straight Alpha):RGB 值按原样存储,不乘以 Alpha;
- 使用原因:在图像编辑应用程序和需要单独的 RGB 和 Alpha 通道操作的场景中很常见;
- 缺点:多存储了 Alpha 信息;如果渲染器只支持预处理 Alpha 模式则会出现渲染错误;
所以当我们使用 PNG 图像作为粒子的材质时候,需要进行一个转换(使用 Python 在本地运行转换程序或使用 WenBo 提供的 在线转换工具)。以上对于材质的讨论都可以利用代码直接在 Xcode 中实现,相比 RCP 有几点需要注意的事情:
- 因为读取材质(特别是分辨率高的且为 HDR 材质)是一个耗时的操作,在实际工程中建议将材质读取过程放到类成员初始化的时候去做,下面的代码仅做一个演示。
- 相比 RCP,代码中没有 is Animation 这个选项,对应的只有初始化了
imageSequence
这个实例属性,之后的参数设置(比如rowCount
等)才生效。
💡 如果想要显示粒子材质的原始颜色,需要将粒子的颜色设置成单色白色
下面我们继续讨论单个粒子的属性配置。除了我们之前说到的粒子大小,我们可以对单个粒子的出现进行更详细的设置,比如 Size Over Life 控制粒子从出现直到消失这个过程的缩小比例,默认是 0.1。而 Size Over Life Power 则是控制缩小比例变化的快慢,参数设置为 1 时呈线性,小于 1 转变较快,大于 1 转变较慢。
另外还有 Mass、Life Span、Angle 以及 Angular Velocity 参数,其控制的内容如下图所示
Properties 最后一个参数是 Orientation Mode,控制的是粒子是否以及如何朝向相机的模式,目前的粒子系统提供了三个可选项:billboard,billboardYAligned 以及 free:
具体来看就是选用 billboard 则无论从哪个角度看,粒子始终正面朝向相机,而选择 billboardYAligned 则从 Y 轴看会“穿帮”,如下图所示。当然现在的粒子系统的 Orientation Mode 还比较基础,但是其迭代更新也很快(相比 visionOS 1 beta 1 的只有 billboard 模式目前已经增加到了三种) ,在未来也许会像 Unity 等其它软件一样有更多的朝向选择。
💡 Unity 里有 SketchedBillboard,HorizontalBillboard, VerticalBillboard,Mesh 等选择,下面这个来自 three.quarks 的视频展示了区别。从左到右分别是 HorizontalBillboard, VerticalBillboard 以及 SketchedBillboard:
我们还可以通过 Motion 以及 Force Fileds 中的参数对粒子进行运动的控制。
在 Motion 中的 acceleration 以及 dampingFactor 分别控制了粒子运动的正负加速度。也许有小伙伴会问这个和之前的 Speed 参数有什么区别?我们可以理解成同一时间对粒子运动距离的控制,比如说同样是 1 秒内,不设置这两个参数则粒子是匀速运动,这两个参数可以控制粒子加速或减速运动。
而利用 Force Fileds 中的参数则可以实现类似旋风、涡流、引力的效果。Noise 参数控制 Turbulence 的程度,给粒子的运动带去了随机性、变化性和复杂性。为什么要这么做呢,因为这增加了真实感(许多自然现象都是由结构性和随机性组合而成的),我们有三个参数可以用于控制随机性的规模、强度与变化速率,如图所示。
💡 一般什么时候需要引入随机噪声呢:
烟雾和火焰。Turbulence 对于创建逼真的烟雾和火焰效果至关重要。 它引入了现实生活中烟雾中不可预测的波浪运动。
水和流体。对于水模拟,Turbulence 会引入在实际流体流动中观察到的混沌漩涡和涡流。
漂浮粒子:对于灰尘或花粉等粒子漂浮在空气中的场景,Turbulence 可以使它们的路径看起来随机且自然。
相比之下更均匀的场力控制参数有 Attraction Center 和 Attraction Strength。另外我们还有 Vortex Direction 和 Vortex Strength 分别控制涡旋的轴方向和强度。
💡注意,这个涡旋轴方向并不是粒子受到力的方向,如下图所示,粒子受到的力方向由粒子的位置与涡旋的轴的叉积决定。当粒子发生运动之后位置会发生变化,所以受力的方向也是实时变化的,最终就形成了漩涡的效果。
粒子发射器里面最后一个我们没有涉及到的参数模块,就是与渲染(Render)相关的。其中 Lightling Enable 主要是控制粒子是否会受到场景照明的影响。(默认 RCP 应该有一个和 Xcode 中一致的 Image based Light 的 HDR 图,Xcode 中可以修改这个系统 IBL 纹理,而实际应用中,粒子受到的照明影响还会根据环境纹理进行叠加)
Sort Order 则会决定粒子的渲染顺序,下图展示了一些不同选项的效果对比。因为在 visionOS 上使用粒子效果的时候允许用户自由的从各个角度去查看,所以这些渲染顺序主要影响的是对于粒子效果深度的感知。
💡 上面这个 demo 我们使用了 Vortex Strength = 1, Vortex Direction = (1, 0, 0) 的参数 _。其中在使用 Force Fields 的时候,请注意力场作用域是全局还是局部,如果是全局,则使用同样配置的场力控制参数的粒子表现会受到同一力的作用,如下所示展示了三个粒子效果受到全局的 vortex 参数控制形成的漩涡效果。
Blend Mode 则决定了粒子颜色的呈现模式。目前最常用的是 alpha 混合模式。
TADA!关于粒子发射器的所有参数细节我们都讨论完了,而正如我们之前说到的复杂粒子效果,比如发射烟花,需要发射器之间有相互关联,目前的粒子系统只支持 2 个发射器之间关联,通过 Spawn 的相关参数进行控制。其中 Spawn Occasion 是最重要的控制参数,它决定了 spawn 粒子相对于主粒子什么时候发射,默认是主粒子发射结束后产生 spawn 粒子,除此之外还有其他三个选项,如下图所示。
💡 onCollide 目前在 RCP 上无效。
除此之外还有 Spawn Velocity Factor 控制 spawn 粒子的速度,以及 Spawn Spread Factor 控制扩散角度(这个参数有增加随机性的 Variation)。spawn 粒子发射器的可选配置则与主粒子发射器完全一致,这里不再赘述。
进阶粒子效果以及粒子的应用
上面我们是深入粒子的各方面细节进行剖析,下面给大家展示一些具体的粒子效果:
💡 当创建粒子效果时,使用一个参考物体是个好主意。这样,你可以轻松地判断粒子的实际大小,确保它既不太小也不太大。
- 我们强烈建议您查看 WWDC 会议的两个专题:Enhance your spatial computing app with RealityKit 和 Build spatial experiences with RealityKit. 。session 里为我们提供了关于高级粒子效果的深入见解,以及如何使用自定义 system 以及将其注册到我们的应用中,并高效地管理粒子的更新。
那么大家可能会问粒子有哪些应用呢?当然具体的使用方式要由屏幕前的你来定义!在这里我们通过一些影视作品的特效和已有的一些工程案例,希望能给大家一些灵感:
- 结合手势的随时随地心情表达
在 2D 的手机屏幕里面,我们通过点赞表达对朋友圈的认同,我们一键三连表达对视频的认可,在空间计算中我们是不是可以利用手势识别随时随地表达我们的心情、态度呢?
大家是否还记得在 XR 世界导览 NEWSLETTER #009 里面我们介绍的,在 iOS 17 的 Facetime 中我们已经可以使用一些简单的手势激活特效了
- 社交应用中的魅力展现
在洛基剧集中,洛基通过魔法在手上放出烟花给希尔维看。那么虚拟社交应用中,我们是不是可以通过烟花、气球、盛开的玫瑰等随时随地和朋友进行互动,展现一些别样的魅力呢?
洛基第一季第三集,视频来自网络,版权归漫威所有
- 3D 交互中的过度动画
在二维交互的时候我们可以通过动画优化各个元素变化时候的用户体验,在三维交互时,粒子则是各种模型出场退场最好的过渡效果小帮手了。比如下面 Tassilo 结合绘制与 AIGC 创建独特的壁画时,转变的过程中就是利用粒子效果来帮助模型的过渡。
总结
在 3D 场景中使用粒子可以显著增强环境或动画的真实感、沉浸感和视觉吸引力。
- 真实感:许多自然现象(如烟、火、雨和雪)都很复杂,无法手工建模或制作动画。 粒子系统可以高度真实地模拟这些效果。
- 效率:粒子不是对数千个单独的对象进行建模,而是允许您使用单个系统来表示大量相似的对象,例如一群鸟或一群人。 这可以提高内存和计算效率。
- 随机性:粒子系统可以引入随机性,确保火花、水花或落叶等效果不会显得过于均匀或可预测。 这种可变性可以使场景看起来更加有机,而不是计算机生成的。
- 交互性:粒子系统可以响应视频游戏等实时环境中的玩家动作。 例如,角色在水中行走可能会产生涟漪和飞溅,或者爆炸可能会产生动态的烟雾和碎片云。
- 吸引力:除了现实主义之外,粒子还可用于风格化的视觉效果,为场景增添风格和艺术吸引力,例如神奇的光环、发光的轨迹或梦幻般的氛围。
- 增强叙事:粒子可用于强调和支持故事元素。 例如,尘土飞扬的环境可以显示出一个地方的年代久远和疏忽,而随风飘扬的樱花则象征着浪漫或宁静的时刻。
总之,粒子系统是 3D 应用的重要工具,许多效果的呈现是其他方法难以实现的。 使用粒子可以使场景栩栩如生,使用户更加引人注目和身临其境。虽然目前 Apple 的粒子系统还比较简单但也非常实用,我们期待了解大家在自己的应用中是如何使用粒子效果!
本文作者
Link | Image |
---|---|
章子飏 |