游戏引擎中的粒子和声效系统
游戏引擎中的粒子和声效系统
粒子基础

粒子简单来看就是空间中的一个小点
粒子具有速度,位置,颜色,生命周期,大小等属性

粒子的生命周期中,包含产生(Spawn)、与环境交互以及死亡时间。
粒子的生命周期管理不好会导致系统资源消耗殆尽

粒子发射器有三个作用:
- 具体规定粒子产生的规则
- 具体规定粒子模拟的逻辑
- 描述如何渲染粒子
一个真实的粒子效果是由多种不同粒子效果叠加而成的
粒子系统 Particle System

粒子系统是一组粒子发射器的组合
粒子系统经常有不止一类发射器,比如火堆这个系统中有火焰、火星和烟雾三种发射器

上图的子弹击打地面包含烟尘,四周扩散的碎片等效果,由特效师去组合完成。

粒子生成的位置变化可以基于单点扩展、在空间区域上衍生和在mesh上生成

在生成模式上可以持续产生, 间歇性产生
粒子的模拟
粒子被发射出来后在空间的所有行为就叫做simulate

常规的影响 --- 重力,空气阻力,风的扰动

粒子系统精度要求不高,选择开销小,最简单的显示积分


模拟时,除了重力,还可以加上粒子的旋转、颜色的变化、大小的变化以及和环境的碰撞等

粒子的形状一般有三类, 下面会详细展开

这种粒子由一些面片构成,其形状其实只有一面,但它始终保持面向摄像头,所以看起来是一个3D的粒子。
如果这个particle比较小就无所谓,但如果比较大的时候建议是其形状也会随时间而变化,不然比较假。

要模拟散的碎的粒子时往往直接用3D mesh当做粒子,然后给它们设置各种不同类别的随机属性,从而艺术家也更容易实现想要的效果

样条形粒子,其实粒子是样条上的控制点,然后通过连接获得完整的条状。
往往使用在比如武器挥舞的残影之类的地方。在控制点连接过程中需要插值,不然每一个连接点间的形状是不连续的(看起来像一个个四边形拼在一起)。
一般使用向心的catmull-rom插值(在粒子间加入额外的分割块且数量可自己选定,不过对CPU要求会变高)


粒子渲染 Particle System Render

常见的透明融合问题在粒子渲染时也需要解决,排序一定要从远到近。

粒子排序有两种方式,一种是全局法,完全按粒子个体来排序,很精准但消耗巨大;
另一种是按层级,从简单到复杂的排序是依照粒子系统排序、依照emitter排序和在emitter之内排序,表达效果会存在问题。
具体来说,如果依照粒子排序,则按粒子离相机的距离排序;如果按系统或发射器排序,则按Bounding box排序。

粒子系统的不透明物体渲染开销非常大

优化:降分辨率下采样进行粒子的渲染,此时与原场景无关,获得粒子的颜色和透明度alpha。然后再采样融合到原场景中。
在GPU进行粒子运算

粒子系统这种海量的信息处理适合在GPU上进行,但问题是粒子拥有生命周期,会不断产生消失,所以如何在GPU中实现粒子是一个难点
解决方案:

初始化状态 ---- 先建立一个粒子池,设计一个数据结构,设定系统包含的粒子总数量,每个粒子的位置、速度等。
再有两个list,一个是Dead List,记录当前死亡的粒子,初始时包含所有粒子序号,还有一个是alive list,记录当前活着的粒子,初始时为空。
比如emitter发射了5个粒子,则从池子结尾取5个粒子(序号)放入alive list,同时把dead list的后5个序号清空。

模拟 ----- 当时间跳转到下一次tick时,会新建一个alive list1,并依序检索alive list中的粒子,如果发现某个粒子死亡了,就会把这个粒子序号移到死亡列表中,并且在渲染时也跳过这个粒子,如果仍存活就照抄到alive list1中。
这个操作因为compute shader的发明变得容易,因为compute shader可以进行原子级操作。
同时,在更新完活着的粒子之后,还可以利用GPU进行frustum culling视角剔除(针对活着的粒子),并且计算它们的距离,写入距离buffer。

接着,还需要进行排序、渲染和交换alive list:
- 排序。根据距离buffer对活着的剔除后的粒子排序
- 渲染。对排序后的粒子渲染
- 交换。交换alive list1和alive list,更新存活列表。


具体来说排序。GPU的排序类似归并算法,复杂度为nlogn。
采取的方式是针对目标序列(排序后)的每一个位置设置一个线程,考虑它应该从两个列表中哪个取得。
这样做会比每个源列表位置一个线程去考虑插入到哪里更简单,因为后者会让“写过程”跳来跳去不连续。

同时利用深度缓冲还可以进行碰撞的检测,具体:
- 把粒子的当前位置投影到上一帧的屏幕空间纹理坐标
- 读取上一帧的深度纹理图中的深度值
- 检查1和2中的深度值,判断是否碰撞了但又没完全穿过去(厚度值会被用到)
- 如果碰撞发生了,就计算碰撞表面法向和粒子反弹的方向
粒子的扩展应用

直接利用粒子来简化模拟物体,比上图动画中的人群。

我们可以把原本一个例子的加速等行为换成更复杂的人体姿态动作,相当于每个particle设置了一个状态机。
我们把这个particle的各种状态和对应的速度等属性的情况设置成一张纹理图。当particle的属性变化时就从纹理图中找到对应的状态不断切换。

在上述基础上,可以利用一个粒子一个人来模拟一个导航纹理图 Navigation Texture。
具体来说,利用SDF来避免人走入建筑物内,然后依次也可以设定一个方向纹理图,当我们给一个粒子设定目的地和初始速度后,它会根据DT的场驱动着往目的地走。
当然,过程中可以加一些随机性。

上图是虚幻的群体模拟,鸟群根据主角位置和环境变化产生一些互动

Info
粒子系统在游戏中的早期应用是“预设型”,即在最初就设定好particle可能的行为,并用stack来表示和存储。
随着游戏的发展又出现了“基于图“的设计,减少代码量增加灵活性;最好的是两者混合型,如上图所示
声音系统 Sound System

声音影响用户对世界认知,感知, 以及情绪的带入。
声音本质是感受到空气中压强的变化,它的主体是一个纵波。
影响声音的三要素如下:



第一要素是声波的声量 Volume
声量由波幅 amplitude 决定
分贝是人类感受的最小压强的单位。
最右图中Lp的公式符合人对声音的自然认知

第二要素是声波的频率 pitch

第三要素是声波的音色 Timbre
音色是不同的基波叠加而成
比如钢琴和小提琴音色区别,它们的频率差不多,叠加基波的权重不同。

降噪耳机的原理是甄别出空气中噪音的一个大概频率,相位,然后耳机再发出同频反向的波与之抵消。

制作游戏引擎需要知道人的听觉范围
如图说话和音乐都在指定的范围
制作声音时,声音频率可能会高于人体的上限,达到一些额外的效果
数字声音 Digital Sound
声音在空气中是无限连续的,游戏中需要把声音变成离散信号

脉冲代码调试器 PCM
对一组波动的信号进行采样, 把采样出来的数据存储为顶点数数据,
然后进行编码进行压缩表达

对任何一个频率的信号,只要采样密度是它频率的两倍,就可以表示无损
实际上对声波的采样超过5K以上

对采样的声音进行量化 Quantizing(bit-depth)处理, 现代音频用14bit或者24bit去存储这个量
对声音感知是非线性的
使用指数的方式去存可以节省存储空间

在游戏中我们常用OGG格式的声音格式,同时无损的数据太大了
因为mp3格式的声音只支持立体声,同时mp3格式有很重的专利保护。
3D Audio Rendering
如何在一个三维空间去构建声音场,这个就涉及到声音的渲染。

在做光学渲染的时候我们需要一个Camera 观察者
在做声学渲染的时候同样我们需要一个Listener 倾听者
Position 会根据游戏的不同,Listener的位置不同,比如第三人称射击游戏会放到摄像机和角色中间的某个点,
Velocity 是多普勒现象考虑的速度, 下面会讲
orientation 决定倾听的角度
Listener表达了一个几何量

人耳对声音很敏感,不仅仅是对于声音的大小,频率,音色的辨认能力很强,并且人耳还对声音到达耳朵的时间感觉很精准。
人耳如何分辨声音的方向的一部分便是通过感受两耳间的时间差。

当speaker有多个channel, 通过调整不同通道上声音的大小,音色,延迟可以产生虚拟的空间感觉
这个就是Panning算法的描述

怎么感受到声音的移动
最简单的做法就是线性地把音强进行移动



人对音强地感知是Power的
为了保证声音的一致性,在声音变化中常用非线性的方法去解决。

声音的衰弱 Attenuation
声音在传播的过程中会有一定的变化。
频率越高的部分在传播的过程中衰减更快,在频率越低的部分在传播过程中衰减的更慢。
所以我们可以根据物体距离Listner的距离设定不同的声音。
比如在吃鸡游戏中在距离开枪声源中等距离的时候高频的混响比较重
跑得再远一点高频的混响会逐渐消失,会听到更多低频的声音。
要求精度比较高的话,会在不同位置时对其插值,如图顶上标注不同距离的声音场
不同的声音衰弱模型

球体–随着距离变化各个方向变化也相同

长圆柱胶囊体–适合流水类型,靠近声音变化大,沿着物体移动声音变化小

盒子–定义空间域模拟被墙阻隔住,出了某个范围迅速衰减

高音喇叭类型
Info
混响的处理也受这些衰减模型影响
环境影响

声音的传播常见的两种阻挡方式
Obstruction:
- 短障碍物让声音在边缘产生新的扩展--波的衍射
Occlusion:
- 长障碍物让声音通过推动障碍物震动后传播

针对两种阻挡方式的不同处理
声音的混响
声音经过环境传播后的叠加

直接到达耳朵的声音叫做干音 Dry
声音打到某个材质上返回后的声音叫做回音 echo
声音来回反弹后产生的尾音 tail(wet)


可以看到不同材质对不同波段的声音吸收不同

混音一些设置参数
声音的多普勒效应


原理-在介质运动时会产生波,以点为圆心扩撒,最后感觉到震动频率就不同
游戏中对速度感知非常重要的效果

追求更好的表现---对整个空间产生采样生成声场

著名的两个声音引擎, Wwise目前发展更好

前沿游戏的运用
PS5的蜘蛛侠把整个城市的混音效果归纳成不同的类型,形成的一个颜色分布图