Quantcast
Channel: 英特尔开发人员专区文章
Viewing all articles
Browse latest Browse all 583

面向视频游戏的流体模拟(第 21 部分)

$
0
0

下载文档

下载面向视频游戏的流体模拟(第 21 部分) [PDF 830KB]

摘要

我们希望打造出内容有趣、图象精美、情节合理的游戏。

流体模拟可以改善游戏机制,增强视频游戏的美感和真实感。视频游戏需要在低预算的情况下实现高性能,但精度要求不高。在低预算方面,我是指计算资源和人力资源:游戏需要快速运行,但不能花费开发人员或美术师大量时间。模拟流体的方法有许多种。在本系列中,我将介绍非常适合视频游戏的方法:便宜,美观,可轻松编写。

如果您要在视频游戏中模拟流体,需要克服很多挑战。流体力学是渗透在数学领域中的一个复杂的主题。它在数字上也充满了挑战性,单纯的实施很不稳定或者操作完全错误,由于流体跨越空间中的每个点,因此,模拟它们需要花费大量计算资源,包括处理和内存两个方面。(尽管流体模拟非常适合在图形处理单元 [GPU] 上运行,但在视频游戏中,GPU 往往会忙于处理渲染。)提高数值稳定性的最简单、最明显的方式是使用更多、更小的时间步进,但这会显著增加计算成本,因此我们倾向于采用能够有效提高流体粘性的其他技术,这意味着游戏中的流体往往会厚而粘稠。诸如光滑粒子流体动力学等最常见的技术不是很适合微妙、朦胧的运动,例如烟雾和火焰。能够解决这些难题的模拟方法有助于在视频游戏中添加更多的流体种类,包括火焰和烟雾。

为了解决这些难题,我提出了一种适合模拟微妙、朦胧的运动的流体模拟技术,该技术基于在任何完整的三维 (3D) 游戏引擎中都可找到的粒子系统模式。它可以使用尽可能多的可用 CPU 线程,线程越多,效果就会越精细。

此方法与游戏开发有很多协同效应,包括以下方面:

  • 游戏引擎支持粒子系统和物理模拟。
  • CPU 往往有未使用的核心。
  • 流体模体适合并行处理。

我提出的方法使用了涡流粒子法 (VPM),这是一种不同寻常的技术,可带来以下优势:

  • 它是一种基于粒子的方法,可重复使用现有粒子引擎。
  • 涡流模拟很适合微妙、朦胧的运动,例如烟雾和火焰。
  • 模拟算法在数值上很稳定,即使没有没有粘性(显式或隐式)也不受影响。

本系列介绍了数学和数值。我提出了基于粒子的流体模拟主题的变体,并纳入了一个热力对流和燃烧的模型,以便系统也可以建立火焰模型。我展示了积分和微分两种数值方法,将它们的优缺点进行对比,提出了一种混合方法,这种方法既能利用每种方法的优点又能避开它们的缺点。这将可以形成一种快速(离子数量呈线性)、流畅的流体模拟,能够模拟朦胧的流体,例如火焰和烟雾。

尽管 VPM 在某些场景中获得了明显的成功,但 它在其他场景中有很大的局限性。例如,它难以显示液体与气体之间的交界处,例如水池表面。我简要地介绍了光滑粒子流体动力学方法 (SPH),以探索一种能够在常见的混合框架中结合 VPM 和 SPH 的方式,但(大体上)我留下了很大的改进空间。

本系列文章留有多个未探索的思路。在文章的结尾,我总结出了我鼓励您探索并与社区分享的思路列表。

第 1 部分第 2 部分概述了流体动力学和模拟技术。第 3 部分第 4 部分提出了一种实时运行双向流-固耦合作用的涡流粒子流体模拟。第 5 部分分析并优化了模拟代码。第 6 部分介绍了另一种用于根据涡量计算流速的方法。第 7 部分展示了如何将流体模拟集成到典型的粒子系统中。第 8 部分第 9 部分第 10 部分第 11 部分介绍了如何在基于涡流的流体模拟中模拟密度、浮力、热量和燃烧。第 12 部分介绍了不恰当的采用会如何导致不必要的跳动,并介绍了如何缓解这种情况。第 13 部分新增了凸多胞形和类似提升的作用力。第 14 部分第 15 部分第 16 部分第 17 部分第 18 部分新增了容器、SPH、液体和流体表面。第 19 部分详细介绍了如何使用树码算法求涡量的积分以计算出矢势。

流体力学

根据我们在建立多个流体模型方面积累的实践经验,我概括了一些这些模拟背后的数学和物理原理。流体模型需要运行数学算法以同时求解一系列方程。每个方程管理流体的物理行为的不同方面。

动量

动量方程(其中一个为著名的纳维尔-斯托克斯方程)描述了动量如何演变以及质量如何移动。这是一个非线性方程,非线性特征是导致流体如此具有挑战性和趣味性的原因。

涡量是动量的旋度。涡量方程描述了流体在何处发生旋涡,即流体在何处以有趣的方式移动。由于涡量是动量的衍生物,因此求解涡量方程相当于求解动量方程。本系列文章利用这种联系,将仅关注流体有涡量的地方的作用力数值,通常流体有涡量的地方比流体有动量的地方稀疏得多。涡量方程还含蓄地舍弃了流体中的分歧,即与流体的压缩性相关的部分。正确处理压缩性需要更多的计算资源或更细微的数值策划,但在与视频游戏相关的绝大多数场景中,您可以忽视压缩性。因此,涡量方程也可产生一种避开压缩性问题的方式。

平流描述了粒子如何移动。动量方程和涡量方程都有平流项。它是非线性项,因此它负责流体运动的最有趣的方面以及最具挑战性的数学和数字问题。使用基于粒子的方法,让我们能够将平流项单独分开来,只需按照流速场在周围移动粒子即可对其进行处理。通过这种方法,可以将 VPM 纳入粒子系统,事实上操作很简单。它还让粒子系统能够重复使用流速场,以用于流体模拟使用的涡流粒子和传播渲染视觉效果使用的“示踪”粒子。

动量方程和涡量方程的浮力项描述了重力、压力和密度如何产生力矩。这种效果蕴含了流体的上升方式,因此对于模拟火焰和烟雾的运动至关重要。注意,虽然本系列中的 VPM 模拟技术未明确建立压力梯度模型,但假设了压力梯度完全沿着重力方向。这一假设让流体模拟浮力,尽管无需将压力作为其单独的部分进行建模。要建立正确的压力梯度模型,通常必须建立压缩性模型,正如在某处所提到的,这通常需要耗费大量计算资源。因此,通过做出压力梯度始终沿着重力方向这一假设,可以看出,能够节约大量计算资源。计算密度梯度需要了解相邻粒子之间的关系。在本系列中,我提出两种解决此问题的方式:基于栅格的方法和基于粒子的方法。基于栅格的方法直接采用一种空间分区方案,该方案也可用于计算粘性效应。基于粒子的方法使用 SPH 使用的算法子集。这两种方法都可以产生令人满意的结果,因此决策取决于哪种方法成本更低。

动量方程和涡量方程中的应力项和应变项描述了压力和剪切如何在流体内产生运动。这就是粘性进入模拟的位置。改变粘性的大小和形式让模拟能够对从烟雾等微妙、朦胧的东西到油或粘液等粘稠的东西等各种流体进行建模。本系列中的流体模拟使用了粒子强度交换法 (PSE) 技术交换邻近粒子之间的动量。该技术需要模拟跟踪粒子邻近的粒子,即了解最近邻的粒子。我提出了一种使用统一栅格空间分区的简单方法,但其他方法也可能有效,这也是我鼓励您进一步探索的思路之一。

涡量方程的伸展项和倾斜项描述了由于配置,一定距离的旋涡之间如何相互作用。严格来说,这就是 3D 效果,它会导致涡旋运动。没有这种效果,流体的行为就少了很多趣味性。我提出的算法使用有限差分计算伸展和倾斜,但其他方法也可能有效。在本文的结尾,我提到了该计算的一个有趣的副作用,您可以使用它来建立表面张力模型。

质量守恒

连续方程说明了,一定体积的质量变化相当于经由体积表面的质量流入量/流出量。正如前面所提到的,本系列中的模拟技术通过施加流体是不可压缩的条件,避开了求解该方程的工作。

状态方程

状态方程描述了流体如何热胀冷缩(以及因此而改变密度)。结合动量方程中的浮力项,状态方程允许算法模拟“热空气上升,冷空气下降”的直观行为。

燃烧

阿仑尼乌斯方程描述了流体的成分如何转变:从燃料转变成等离子再转变成废气。它还描述了液体如何升温因此导致热空气上升,这些将被注入状态方程,以对流体密度如何随着温度的变化而变化进行建模。

拖拽

阻力描述了流体如何与实体相互作用。我提出了一种基于建立粘性模型所使用的 PSE 方法的方法:我在类似的范例中处理了流体粒子和实体。我还将此过程扩展到了交换热量,因此,实体可以加热或冷却流体,反之亦然。

空间分割

流体方程在一个连续的时间和空间域上运行,但在计算机模拟它们需要在时间和空间上分割这些方程。您可以将空间分割为多个区域,这些区域可以移动(例如对于粒子)或不移动(例如对于固定栅格)。

顾名思义,VPM 是基于粒子的方法,而不是基于栅格的方法。然而,我提出的算法也使用了统一栅格空间分区来帮助解答有关空间关系的询问,例如哪些粒子在哪些粒子附近或者哪些粒子在与流体相互作用的实体附近。有很多空间分区可用,并且在每个实施内都可行。针对本文章系列,我选择了适度简单和快速的一部分,但我认为这一过程也可以得到显著改善,因此我在文章末尾提供了一些您可以尝试的想法。

注:其他分割办法也可行,例如在光谱域中。这是为了让好奇的读者知道其他可能性,但为简洁起见,我省去了详细内容。

涡流粒子法

在本系列中,我主要采用 VPM 用于对流体运动进行建模,但即使在该方法中,关于如何执行数值解算器的各个方面,您也有很多选择。最终,计算机需要根据涡量获得流速,并且有两种数学方法来执行此操作:积分和微分。任何一种方法都可以通过多个数值算法进行求解。

我提出的积分方法为直接求和和树码。直接求和具有渐进时间复杂度 O(N2),在提出的所有方法中,该方法是最慢但也是最容易实现的方法。树码具有渐进时间复杂度 O(N log N),该方法介于最慢和最快之间,其代码复杂度明显高于直接求和,但复杂度抵得上速度优势。除这些方法以外,还有其他一些我未涉及的办法可能也可以使用。例如,多极方法具有渐进式的低计算复杂度等级,但在数学和数值上都需要非常高的复杂度。

我提出的微分方法需要求解矢量泊松方程。在我提出的所有方法中,这种方法的渐进运行时间最快,并且数学和代码不是很复杂。基于上述说明,它似乎是一个显而易见的选择,但存在一个涉及边界条件的问题。

求解任何偏微分方程都需要施加边界条件:在域的空间边界处求解方程。对于积分方法,最简单的条件是“开放”,这相当于没有围墙的无限域。模拟算法处理实体,包括墙壁和地板,这些应足以施加适合任何场景几何图形与流体相互作用的边界条件,因此施加更多的边界条件是多余的。

我提出的泊松解算器使用了带统一栅格的矩形盒。在此盒上施加“无滑移”或“无通过”边界条件比较容易,但流体好像在盒内一样进行移动。您可以移动域边界,使其远离流体运动有趣的部分,但由于此盒具有统一栅格,大多数的栅格单元本身会没有任何有趣的地方,但会耗费内存和计算过程。所以,理想情况下,您将有一个支持开放边界条件的泊松解算器,这相当于了解边界处的解,但泊松解算器又是为了获取解,因此是循环依赖关系。

为了解决这一问题,我使用了积分方法计算域边界(二维表面)处的解,然后使用泊松解算器计算整个域内部的解。该混合方法运行 O(N) 时间(比树码快),但其结果优于树码解算器结果。

评估

VPM 很适合火焰和烟雾,但不适合液-气边界。SPH 很适合液-气边界,但不流畅。我尝试将两者结合起来但效果不佳,但我认为这种方法是有价值的。

更多可能性

我在本系列中提出的方法和代码提供了示例以及针对游戏视频的流体模拟的出发点。要将这些示例转变成可行的产品代码,需要进一步完善模拟和渲染代码。

模拟

VPM 改进

我实施了一个简单的统一栅格空间分区方案。对该数据结构执行查询会耗费大量时间。您可以对其进行优化或进行更换,例如使用空间散列。您也可以将每个单元容器换成更轻巧的容器。

尽管比较困难,但还是可以对 VPM 中的这些液-气边界进行建模。您可以通过使用水平集跟踪平面,使用表面几何图形计算曲率,使用曲率计算表面张力,并将这些效应纳入涡量方程。计算曲率需要计算 Hessian,它与 Jacobian 有关,而 Jacobian 已被用于计算应变和应力。

VPM 有一个明显的数学问题:首先是一束小粒子携带一个极小区域中的涡量,非常之小,容易将它们视为点。涡量在数学上就像一个磁场,您可以将这些涡流粒子比作为细小的磁体。然而,这些磁体只有一个“极”,这在数学和物理上都是不可能的。同样,不存在像涡流“点”的东西。如果您只有一个点,涡流场可能存在分歧,而这在数学上是不可能的,在物理上也是毫无意义的。然而,此模拟方法正是存在此问题。解决此问题的一种方式是使用涡流线,例如拓扑上形成的环。封闭涡流环没有净分歧。(例如,请参见 Angelidis 和 NeyretSee 共同撰写的“Simulation of Smoke Based on Vortex Filament Primitives” 。)涡流线也可以在流体边界处终止,例如在与实体的交界处。旋转体是一个最明显的示例:事实上,旋转体有一个涡量,涡线应通过旋转体。

注:在 SIGGRAPH 2010 上发表的“Filament-Based Smoke with Vortex Shedding and Variational Reconnection”出现了以下错误:作者将旋转体置于流体内,但他们的涡流线没有通过这些旋转体。他们好像在后续期刊上更正了此错误,并且曾出现此错误的 YouTube* 视频不再可见。

其他技巧

因为 SPH 也是一个使用粒子的流体模拟方法,所以我的直觉是,它应会对 VPM 起到补充作用,以便一些混合方法可以既适用于朦胧的流体,也适用于液状或粘稠的流体。我不会说我的尝试成功,但我希望它可以激发出统一这些方法的设想。尽管我的实施失败,但我认为基本思路仍是有效的。

本系列文章没有涉及它们,但基于栅格的方法非常适合特定情况,例如当势流很重要时以及浅水波等。同样,谱方法具有极高的准确性,但这正是视频游戏所舍弃的东西。

渲染

在伴随这些文章的代码中,大多数处理时间用在渲染方面,而不是模拟。这是个好消息,因为示例代码中的简单渲染没有利用现代 GPU,因此有很多提高速度的机会。

示例代码执行多个顶点操作,例如计算面向相机的四边形。该代码易并行,因此可编程顶点着色程序可在 GPU 上快速执行该代码,因为 GPU 有数百个或数千个处理单元。

然而,结果证明,在每个顶点上操作的例程上添加更多 CPU 核心不会产生线性加速,这意味着内存带宽限制处理速度。事实上,要加速处理,机器需要访问更少的内存。此外,有解可供使用:在顶点缓冲区内,每个粒子仅存储一个元素,而不是每个三角形顶点存储一个元素。甚至可按原样传输一份粒子缓冲。由于您可以控制顶点着色程序如何访问内存,该顶点缓冲可以采用您喜欢的任何格式,包括粒子缓冲拥有的格式。这意味着使用更少的带宽。

注意,GPU 很可能仍需要一份单独的粒子缓冲,即便其内容与 GPU 使用的粒子缓冲完全相同。原因是这些处理器异步运行,因此,如果它们共享了一个缓冲,CPU 可能会在 CPU 访问数据的中途修改粒子缓冲,这会导致不一致的渲染伪影。在这种情况下,复制粒子缓冲较为谨慎。(也许直接存储器存取引擎可以进行复制,且不会妨碍 CPU。)相比之下,渲染共享粒子缓冲的视觉伪影可能会非常之小和罕见,以致于用户可能没有察觉到。您应该尝试多个变体,以便在速度和视觉质量之间达到平衡。

为了使流体模拟看起来像连续、稠密的流体,而不是一系列稀疏的点,示例代码使用了大量示踪粒子,实际有数万个的示踪粒子。可以说,如果有数百万粒子,效果会更好,但处理和渲染的计算费用很高昂,无论是在时间上还是在内存上。如果您使用更少数量的同等大小的粒子,渲染效果会留下间隙。如果您增大粒子大小,间隙会消除,但流体可能会看起来比较朦胧,也就是说除非粒子仅沿着可能出现更小粒子的方向增大。此问题至少有三种解决方法:

  1. 使用立体渲染替代粒子渲染。这样做会涉及计算体纹理和使用更少数量的更大面向相机四边形访问体纹理进行渲染;效果会很棒。
  2. 沿示踪粒子伸展的方向伸长示踪粒子。其中一种方式是将示踪粒子视为成对配对,在这种情况下,它们在彼此附近初始化并作为胶囊形的两端进行渲染,而不是将每个粒子作为单独的 blob 进行处理。您甚至可以将其与用于跟踪上,即和当前相机变化的着色程序相结合,引入一个简单而有效的运动模糊;两者的数学运算都较为类似。
  3. 展开选项 2 的思路,甚至可以使用更多的成对示踪粒子系列。例如,您可以四个(或者您选择的数量 N 个)为一组发射示踪粒子,并将它们渲染成一条丝带。然而,注意,如果粒子群“扭结”,渲染可能会非常棘手;这会导致丝带折叠部分,因而屏幕空间会出现零区。

关于作者

Michael J. Gourlay 博士就职于 Microsoft,在“环境理解”小组担任 HoloLens* 主要开发负责人。他领导团队实施跟踪、表面重构和校准。他之前就职于 Electronic Arts (EA Sports),担任足球运动业务部门的软件架构师、Madden NFL* 高级首席工程师、角色物理学和 ANT*(EA 使用的程序动画系统)高级首席工程师、综合格斗* 高级首席工程师、FranTk*(Connected Careers Mode 背后的引擎)原架构师、NASCAR* 主程序设计师。他编写了 Lynx*(全球 EA 游戏中使用的视觉特效系统)和获得专利的高带宽在线互动应用程序算法。

他还开发了相关课程,在中佛罗里达大学、佛罗里达互动娱乐学院,以及最顶尖的旨在教授程序员、制作人和艺术家如何制作视频游戏和训练模拟的跨学科研究生项目中从事教学工作。

加入 EA 之前,他使用计算流体动力学和世界最大规模的并行巨型计算机开展了科学研究。Michael 分别获得了乔治亚理工学院和科罗拉多大学博尔德分校颁发的物理学学位和哲学学位。


Viewing all articles
Browse latest Browse all 583

Trending Articles