想象你站在灶台前,锅里炖着一锅浓汤。你用木勺沿着锅边缓缓搅动,香料和油花跟着汤流旋转;火候加大时,热气升腾,汤面泛起细密的泡沫。电影里的烟雾和火焰,其实就是在电脑里“炖”这样一锅虚拟的汤。虚拟的汤不是食材,而是速度、压力和密度这些看不见的数值;搅动的勺子相当于我们施加的力,火苗相当于燃烧反应,而锅里每一处汤的状态,就是我们要模拟的流体。为了让这锅汤看起来逼真,我们要把锅切成许多小格子,像用豆腐模子把整块豆腐切成小方块,然后在这每个小方块里计算汤的流动、温度和浓稠度。最后再用“半透明果冻”的方式,把密度变成颜色和亮暗,渲染成屏幕上袅袅升起的青烟和跳动的火焰。这篇文章会带你看懂这整套过程:从物理方程、网格划分、数值求解,到边界条件、烟雾密度、火焰燃烧和体积渲染,以及如何在游戏里实时跑起来。

岗位关联

掌握这套流体模拟链路,你就掌握了影视特效、游戏开发和虚拟仿真中最有辨识度的视觉技术,能让你的作品从“普通”跃升为“大片级”。

目录
  1. 可视化演示
  2. 流体运动方程
  3. 体素网格离散
  4. 数值求解算法
  5. 边界条件处理
  6. 烟雾密度场
  7. 火焰燃烧模型
  8. 体积渲染管线
  9. 实时优化策略
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示流体模拟中体素网格密度场、Navier-Stokes速度场求解、以及体积渲染的温度着色过程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+_captions.voxel+'

流体运动方程

想象你在灶台上炖了一锅浓汤,用木勺沿着锅边匀速搅动。汤里每一滴香料都在旋转,但不同位置的旋转速度并不相同:靠近勺子的地方转动快,远离勺子的地方转动慢。搅动停止后,汤也不会立刻静止,而是因为粘性慢慢平复。烟雾和火焰模拟的起点,就是把这样一锅汤的每一个细节转换成数字。

电脑要模拟这锅汤,首先要定义每个点的状态。每个点包括速度(朝哪个方向流、多快)、压力(前后左右的挤压力)和受到的力(重力、浮力等)。这些状态合在一起,构成了流体运动方程——Navier-Stokes方程。它告诉我们:任意时刻,任何位置的速度变化率等于自身运动带来的平流、压力差、粘性扩散和外力四部分之和。

电影里冲天烟柱、缓缓飘散的雾,本质上都是这个方程在虚拟空间里被反复求解的结果。相当于我们不断地问:此刻勺子往哪边发力?汤往哪边流?然后更新所有位置的速度。

∂u∂t=−(u⋅∇)u−1ρ∇p+ν∇2u+f\displaystyle \frac{\partial \mathbf{u}}{\partial t} = -(\mathbf{u}\cdot\nabla)\mathbf{u} - \frac{1}{\rho}\nabla p + \nu \nabla^2 \mathbf{u} + \mathbf{f}
这个方程像一张“菜谱”,把速度变化拆成了四个动作:跟着汤流走、被压力推、被粘性抹平、被外力拉。
  1. 速度变化率左侧表示某个位置的速度随时间的变化,相当于“这一瞬间汤流的速度是加快还是减慢”。
    ∂u∂t\frac{\partial \mathbf{u}}{\partial t}
  2. 自身平流第一项表示流体被自己带着走,就像漩涡带着周围的汤一起转。
    −(u⋅∇)u-(\mathbf{u}\cdot\nabla)\mathbf{u}
  3. 压力项第二项是压力差造成的推力,高压处会向低压处加速。
    −1ρ∇p-\frac{1}{\rho}\nabla p
  4. 粘性项第三项让相邻速度差被“抹平”,浓汤比清水更粘,所以纹路更缓慢。
    ν∇2u\nu \nabla^2 \mathbf{u}
  5. 外力项最后一项是重力、浮力等外部影响。
    f\mathbf{f}

体素网格离散

要让电脑计算这锅汤,不能把每个物理点都记下来,那样数据量是无穷的。就像做豆腐时,把整块豆腐切成整齐的小方块,我们再把空间切成一个个小立方体,每个立方体里只保存一组平均的速度和密度值。这些立方体在图形学中叫体素,由它们组成的网格称为体素网格。

切多细是关键。切得越细,能表现越丰富的漩涡和烟雾纹理;切得越粗,细节被平均掉,像把汤煮成了米糊。通常用分辨率描述切分密度,比如 128×128×128 表示在三个方向各切 128 份。数值求解时,导数也不再是连续公式,而是相邻格子之间的差商。

选择网格分辨率,就像在“细节”和“锅的大小”之间做取舍。电影工业模拟可以使用上亿体素,游戏里则只能精打细算,用少得多的格子加上技巧补救。

∂u∂x≈ui+1−ui−12Δx\displaystyle \frac{\partial u}{\partial x} \approx \frac{u_{i+1} - u_{i-1}}{2\Delta x}
这个公式把“无穷小”换成了“相邻格子之差”,是连续世界走向离散网格的关键一步。
  1. 邻格差值用左右邻居格子的速度差除以两倍间距,近似表示该点的空间变化率。
    ui+1−ui−12Δx\frac{u_{i+1} - u_{i-1}}{2\Delta x}
  2. 间距决定精度Δx 越小,近似越精确,但格子数量会急剧增加。
    Δx\Delta x
  3. 格子编号下标 i 表示第 i 个格子,u_i 是该格子中心的速度。
    uiu_i

数值求解算法

光是知道方程不够,还要有炖汤的步骤。电脑没法直接解出整个汤锅的最终状态,只能把时间切成很多小步,每一步都根据当前状态推算下一个小步。这个“一步一步炖”的过程就是数值求解。

最常用的思路是投影法:先粗略地预测一步速度,然后求解压力,再用压力把速度修正到符合流体不可压缩的性质。不可压缩性可以简单理解为:汤的体积不会突然胀大或压缩,各处的流入和流出必须平衡。

这就像你先估计汤接下来会怎么流,再检查有没有某处汤被“压扁”或“撑大”,若有,就用压力把它推回原样。每一步都在做这个“预测—修正”循环,虚拟汤才能稳定地翻滚。

∇2p=ρΔt∇⋅u∗\displaystyle \nabla^2 p = \frac{\rho}{\Delta t}\nabla\cdot\mathbf{u}^*
这个方程是在问:为了消除速度场中的“膨胀”,压力应该长成什么样?
  1. 预测速度忽略压力,仅用平流、粘性和外力得到一个中间速度 u\*。
    u∗=un+Δt(−(u⋅∇)u+ν∇2u+f)\mathbf{u}^* = \mathbf{u}^n + \Delta t\left(-(\mathbf{u}\cdot\nabla)\mathbf{u} + \nu\nabla^2\mathbf{u} + \mathbf{f}\right)
  2. 压力泊松方程对中间速度求散度,再通过泊松方程解出压力 p,散度不为零的地方正是需要压力修正的地方。
    ∇2p=ρΔt∇⋅u∗\nabla^2 p = \frac{\rho}{\Delta t}\nabla\cdot\mathbf{u}^*
  3. 速度修正用压力梯度修正预测速度,使最终速度的散度为零。
    un+1=u∗−Δtρ∇p\mathbf{u}^{n+1} = \mathbf{u}^* - \frac{\Delta t}{\rho}\nabla p

边界条件处理

锅壁和锅盖决定了汤的活动范围。如果没有边界条件,汤会从锅里流到桌面上,再流到地板。模拟中也要为虚拟空间指定边界:墙壁、入口、出口和开放空间,它们统称为边界条件。

常见的边界条件有几种:壁面边界模拟刚性墙,流体不能穿过,墙的法向速度为零;流入流出边界模拟风扇、烟囱、火源,持续注入物质或能量;开放边界允许流体自由离开,比如舞台上的烟被剧场通风吸走。

边界条件把这些现实中的阻挡和出口翻译成数学规则,让虚拟汤被框在屏幕的世界里,而不是漫无边际地消失。少了它,火焰会烧穿整个场景,烟雾也会“漏”到屏幕外。

u⋅n=0(壁面)uwall=−uinside(反射)\displaystyle \mathbf{u}\cdot\mathbf{n} = 0 \quad \text{(壁面)} \qquad \mathbf{u}_{wall} = -\mathbf{u}_{inside} \quad \text{(反射)}
壁面条件就像在提醒每一个格子:锅壁挡着,别把汤洒出去。
  1. 法向速度为零在壁面上,垂直方向的速度分量为零,表示流体无法穿过墙壁。
    u⋅n=0\mathbf{u}\cdot\mathbf{n} = 0
  2. 反射边界如果采用反射模型,壁面内外的速度镜像反向,模拟流体碰撞后回弹。
    uwall=−uinside\mathbf{u}_{wall} = -\mathbf{u}_{inside}
  3. 开放边界在出口处不限制速度,允许烟雾逸出计算域。
    ∂u∂n∣out=0\left.\frac{\partial \mathbf{u}}{\partial n}\right|_{out} = 0

烟雾密度场

烟是什么?在我们看来是灰黑色的、在水中扩散的颜料。对模拟器来说,烟只是一个标量密度场:每个格子里有一个数,表示这里有多少烟雾物质。密度高,颜色浓;密度低,颜色淡。

密度场不能静止,它会被速度场带动,这叫平流,就像香葱被汤流带到锅的另一边。同时,烟雾分子还会从高浓度向低浓度扩散,把边缘变得柔和。火源或烟源每帧往某些格子注入新的密度。为了让烟最终消散,还要让密度逐渐衰减。

于是,肉眼看到的烟柱、翻卷、扩散、消失,都变成密度场上一个个数字的移动、累加和衰减。掌握密度场,就掌握了烟雾“有没有、有多少”的核心。

∂ρ∂t=−(u⋅∇)ρ+κ∇2ρ+S−λρ\displaystyle \frac{\partial \rho}{\partial t} = -(\mathbf{u}\cdot\nabla)\rho + \kappa \nabla^2 \rho + S - \lambda\rho
密度场的演化包含平流、扩散、注入和衰减四件事,像汤里的香料被冲散又慢慢沉淀。
  1. 密度平流密度随速度场移动,香料被汤流带到各处。
    −(u⋅∇)ρ-(\mathbf{u}\cdot\nabla)\rho
  2. 扩散κ 是扩散系数,让浓密度慢慢均匀,烟团边缘变柔和。
    κ∇2ρ\kappa \nabla^2 \rho
  3. 源项S 是从烟源/火源新注入的密度。
    SS
  4. 衰减λ 表示烟雾随时间消散,让烟最终消失而不是永远堆积。
    −λρ-\lambda\rho

火焰燃烧模型

火焰和烟的区别在于燃烧。火焰不是一团被推着走的颜色,而是一个持续发生的化学反应:燃料与氧气在高温下快速反应,释放热和光。在模拟中,我们会准备一个燃料场,像锅里的油;再准备一个氧气场,像空气中的气。

每个格子的燃烧速率要看燃料和氧气是否充足,还要看温度是否达到着火点。温度越高,反应越快,放出更多热,又进一步加速反应,形成火焰那种跳跃、翻卷的动态。这个“越烧越旺”的非线性放大,正是火焰比烟雾更难模拟的原因。

这就像看着灶台上火焰的颜色,你能猜到哪边火更旺。燃料耗尽、氧气不足、温度过低,任何一个条件不满足,火苗都会抖动甚至熄灭。

R=k ρfuel ρoxygen exp⁡(−EaRT)\displaystyle R = k\, \rho_{fuel}\, \rho_{oxygen}\, \exp\left(-\frac{E_a}{RT}\right)
阿伦尼乌斯公式描述了温度升高后燃烧如何指数级加速,是火焰动态的灵魂。
  1. 反应速率R 表示单位时间内消耗的燃料量,直接决定火焰的亮度与热量输出。
    RR
  2. 浓度乘积燃料浓度乘氧气浓度,任何一方不足都会压低燃烧速度。
    ρfuel ρoxygen\rho_{fuel}\, \rho_{oxygen}
  3. 指数加速温度 T 在分母上,温度越高,指数项越接近 1,反应急剧加快。
    exp⁡(−EaRT)\exp\left(-\frac{E_a}{RT}\right)
  4. 温度映射颜色模拟结束后,根据温度给火焰着色,高温区偏蓝白,低温区偏橙红。
    T→colorT \to color

体积渲染管线

当密度场和火焰温度算好之后,还要把它变成屏幕上每个像素的颜色。烟雾是半透明的,没有清晰表面,所以不能像渲染球体那样只算表面,而要像看一块果冻:透过不同厚度的果冻,看到的颜色和亮度都不同。

体积渲染最常用的方法是光线步进。从相机出发,对每个像素发射一条光线,光线穿过体素网格,每隔一小段距离取样一次密度和颜色,根据透明度累积。光线前面被遮住的物质越多,后面越模糊。

这就像你透过一层层薄纱看灯光,每一层薄纱都吸收一点光、散射一点颜色。累积起来,就有了烟雾那种蓬松、有体积感的效果。

C=∑i(1−Ti) αi ci,Ti=exp⁡(−∑j<iσjΔx)\displaystyle C = \sum_{i}(1 - T_i)\, \alpha_i\, c_i, \qquad T_i = \exp\left(-\sum_{j<i}\sigma_j \Delta x\right)
每走一步,都要问:前面已经挡了多少光?这一步应该透出多少颜色?
  1. 光线步进从相机出发,沿光线按步长 Δx 采样体素,每次采样都计算当前点的颜色和遮挡。
    Δx\Delta x
  2. 透射率T 表示光穿透前面烟雾后还剩多少,σ 是吸收系数,烟雾越厚透射率越低。
    Ti=exp⁡(−∑j<iσjΔx)T_i = \exp\left(-\sum_{j<i}\sigma_j \Delta x\right)
  3. 颜色累加每个采样点贡献颜色 c_i 乘以其不透明度 (1-T_i),从近到远逐层累加。
    C=∑i(1−Ti) αi ciC = \sum_{i}(1 - T_i)\, \alpha_i\, c_i

实时优化策略

影视特效可以花几小时渲染一帧,但游戏必须一秒钟画 60 帧。为了实时,要尽量减少计算量。一个直接的思想是:汤里真正有料的格子只占一小部分,没必要保存和处理所有空间。

于是有了稀疏体素网格:只存储密度或速度非零的格子,内存和计算量从全空间量级降到活动体素量级。还可以用多分辨率:近处用细网格捕捉细节,远处用粗网格忽略不会被人注意的差异。此外,湍流细节可以在粗网格上用小尺度噪声或涡度约束补充,制造“细碎卷曲”的感觉。

游戏里的火焰和烟雾才能在手机上流畅舞动,靠的就是“只在需要的地方花力气”。这告诉我们,特效技术不仅追求物理正确,也追求聪明的偷懒。

M=∑i,j,k1(activei,j,k),内存占用 O(M)\displaystyle M = \sum_{i,j,k} \mathbf{1}\bigl(\text{active}_{i,j,k}\bigr), \qquad \text{内存占用 } O(M)
稀疏存储相当于只切有豆腐的格子,而不是切完整个豆腐模子。
  1. 活动体素只有密度或速度超过阈值的格子才被标记为 active,参与计算。
    1(activei,j,k)\mathbf{1}(\text{active}_{i,j,k})
  2. 稀疏存储把活动体素单独存进紧凑数组,内存从 O(N³) 降到 O(M)。
    O(M)O(M)
  3. 多分辨率近处使用细网格 Δx1,远处使用粗网格 Δx2,人眼难以察觉差异。
    Δx1<Δx2\Delta x_1 < \Delta x_2

AI 应用场景

影视级烟火解算

阶段:物理仿真参数智能调优

解决的问题:传统方式下,烟囱和爆炸的仿真参数要手工试错数小时,效果还不稳定。用 AI 回归模型从历史仿真结果中学习参数与观感的关系,可以自动推荐合适的浮力、粘性和涡度参数,让特效师把精力放在艺术表达上。

具体案例:在《流浪地球》类大制作中,爆炸产生的烟雾和火焰需要与实拍素材无缝合成。AI 辅助参数寻优能把“撞运气”式的调参变成可复现的流程,大大缩短解算时间。

游戏引擎中的实时火焰

阶段:实时推理与轻量化部署

解决的问题:手机游戏既要几毫秒内渲染火焰,又要避免发热卡顿。通过稀疏体素和多分辨率网格,再配合 GPU 并行,可以在移动端保持 60 帧;AI 超分辨率技术还能在低分辨率网格上重建高细节烟雾纹理。

具体案例:开放世界 RPG 中的篝火、魔法爆炸和废墟浓烟,使用实时流体求解器配合神经网络降噪,让低配设备也能看到翻滚的烟柱。

消防疏散与烟气流动分析

阶段:仿真数据生成与机理建模

解决的问题:建筑火灾中烟气运动直接影响人员疏散,传统 CFD 仿真计算量巨大。AI 代理模型可以用少量高精度仿真数据训练,快速预测不同火源位置和通风条件下的烟气蔓延路线,供消防预案实时查询。

具体案例:城市地标建筑的数字孪生系统中,接入烟雾与火焰模拟器,结合传感器数据在线更新烟气扩散预测,疏散引导系统据此动态切换逃生通道提示。

Python 演示

python56 行
import numpy as np  def advect(field, vx, vy, dt):    h, w = field.shape    y, x = np.mgrid[0:h, 0:w]    x_src = x - vx * dt    y_src = y - vy * dt    x0 = np.floor(x_src).astype(int) % w    y0 = np.floor(y_src).astype(int) % h    x1 = (x0 + 1) % w    y1 = (y0 + 1) % h    fx = x_src - np.floor(x_src)    fy = y_src - np.floor(y_src)    top = field[y0, x0] * (1 - fx) + field[y0, x1] * fx    bottom = field[y1, x0] * (1 - fx) + field[y1, x1] * fx    return top * (1 - fy) + bottom * fy  def pressure_solve(div, iters=20):    p = np.zeros_like(div)    for _ in range(iters):        p_new = np.zeros_like(p)        p_new[1:-1, 1:-1] = 0.25 * (            p[:-2, 1:-1] + p[2:, 1:-1] + p[1:-1, :-2] + p[1:-1, 2:]            - div[1:-1, 1:-1]        )        p = p_new    return p  def simulate(steps=80):    n = 48    vx = np.zeros((n, n))    vy = np.zeros((n, n))    rho = np.zeros((n, n))    dt = 0.3    for s in range(steps):        rho[n - 7:n - 3, 22:26] += 0.3        vx = advect(vx, vx, vy, dt)        vy = advect(vy, vx, vy, dt)        rho = advect(rho, vx, vy, dt)        vy -= rho * 0.8 * dt        vx *= 0.999        vy *= 0.999        div = np.gradient(vx, axis=1) + np.gradient(vy, axis=0)        p = pressure_solve(div, iters=20)        vx -= np.gradient(p, axis=1)        vy -= np.gradient(p, axis=0)        rho *= 0.995    return rho.mean()  if __name__ == "__main__":    avg = simulate()    print("模拟完成,平均烟雾密度:", avg)
目的:用 48×48 的二维网格实现简化烟雾模拟,包含密度注入、平流、浮力、压力投影和衰减,跑完后输出平均烟雾密度,验证烟雾是否在网格中扩散。
  1. rho[n - 7:n - 3, 22:26] += 0.3在底部固定区域不断注入烟雾,相当于火源/烟源。
  2. rho = advect(rho, vx, vy, dt)让密度场沿着速度场平流,烟团随气流移动。
  3. vy -= rho * 0.8 * dt热浮力:密度越高代表温度越高,向上加速。
  4. vx *= 0.999` / `vy *= 0.999施加轻微阻尼,防止速度无限增长。
  5. div = np.gradient(vx, axis=1) + np.gradient(vy, axis=0)计算速度场的散度,度量体积变化。
  6. p = pressure_solve(div, iters=20)通过迭代解泊松方程得到压力场。
  7. vx -= np.gradient(p, axis=1)用压力梯度修正水平速度,使体积守恒。
  8. vy -= np.gradient(p, axis=0)用压力梯度修正垂直速度,让汤不可压缩。
  9. rho *= 0.995烟雾缓慢消散,模拟真实世界的稀释。

常见误区

误区我以前做游戏火焰,以为只要在火源位置不断发射橙红色粒子,再把粒子变大变小,看起来就像火了。于是所有燃烧特效都是粒子堆出来的,火焰运动完全由预置动画决定。

正解火焰本质是燃烧反应驱动的流体。燃料与氧气混合、温度升高、反应加速,这些过程由流体方程和燃烧模型共同控制。粒子只是最终把温度场、密度场画到屏幕上的可视化手段,不是物理本身。

为何常见:粒子系统实现简单,视觉上很像火,很多低成本的游戏和视频都用它,导致大家误以为粒子就是火焰模拟。

误区看到电影里烟雾细节丰富,以为只要把网格分辨率调高,就能得到同样逼真的效果。于是直接把分辨率从 128³ 改到 1024³,结果内存爆炸、速度慢得像幻灯片。

正解网格分辨率越高,计算量和内存会立方级增长。逼真是“细节与代价的平衡”,要结合稀疏体素、多分辨率和湍流噪声等技术,在有限算力下最大化视觉质量。

为何常见:直觉上“越精细越真实”很容易被接受,但忽略了实时系统对帧率的硬约束。

误区Navier-Stokes 方程听起来高深,我以为只有大型数据中心或专业 CFD 软件才能解,普通开发者只能望洋兴叹。

正解通过半拉格朗日平流、投影法和 GPU 并行,现代游戏引擎已经能实时求解简化版 NS 方程。很多轻量级库在手机端就能跑出不错的 2D/3D 烟雾效果。

为何常见:学术界常常展示高精度、高分辨率的求解,大家忽略了工程上大量有效的近似和加速手段。

误区我以为把粒子变成半透明圆形,再叠加到一起,就是体积渲染。结果显示像一层薄薄的贴图,没有火焰或烟雾那种蓬松的厚度感。

正解体积渲染要考虑光线在密度场中的吸收、散射和透射累积。光线每穿过一段烟雾,能量都会衰减,颜色也会层层叠加,这样才能得到“从里到外都有体积”的质感。

为何常见:粒子动画在屏幕上看起来类似,很多简化的教程也直接用半透明粒子代替体积渲染,容易让人混淆。

误区朋友告诉我给烟雾速度加一点随机噪声就会有湍流效果,我照做后发现烟只是“抖”起来,不像真实烟雾那样有大小不一、互相缠绕的涡。

正解真实湍流是能量从大尺度涡流逐级传递到小尺度涡流的串级过程。随机噪声只能提供表面抖动,缺少物理约束。工业上常用涡度约束、小尺度噪声注入或预计算湍流场来补充细节。

为何常见:短视频上很多“加了噪就变自然”的滤镜效果,让人误以为随机扰动是万能药。

面试题

Q1. 在流体模拟中,Navier-Stokes方程的速度更新主要依赖哪三个相互作用?

单选题 · easy

  • A.平流、压力、粘性← 正确答案
  • B.光照、纹理、材质
  • C.网格、采样、缓存
  • D.密度、温度、速度

答案:A。Navier-Stokes方程把速度变化拆为自身平流、压力梯度、粘性扩散和外力四部分,其中前三项是核心。光照纹理属于渲染,网格采样属于离散化,密度温度速度只是部分物理量,不能概括方程结构。

Q2. 体素网格的“分辨率”主要影响什么?

单选题 · easy

  • A.只有渲染颜色
  • B.细节与计算量← 正确答案
  • C.边界条件类型
  • D.燃料浓度分布

答案:B。分辨率越高,网格切得越细,能表现更小尺度的烟雾细节,但格子数量立方级增多,计算量也水涨船高。渲染颜色、边界条件和燃料浓度都是单独设定的,不是分辨率的直接作用。

Q3. 投影法中,压力泊松方程的作用是什么?

单选题 · mid

  • A.增加湍流噪声
  • B.修正速度不可压缩← 正确答案
  • C.估算火焰颜色
  • D.降低网格分辨率

答案:B。先用外力和平流预测中间速度,再用压力泊松方程把速度中“发散”的部分修正掉,使流体体积不变。湍流噪声和火焰颜色是后期效果,降低分辨率是优化手段,都与投影法无关。

Q4. 下面哪种边界条件最适合模拟“墙壁”?

单选题 · mid

  • A.法向速度为零← 正确答案
  • B.密度完全吸收
  • C.压力无限增大
  • D.速度反向无穷

答案:A。墙不可穿透,所以流体在墙面法线方向的速度必须为零。密度完全吸收是开放边界的一种近似,压力无限增大和速度反向无穷在物理上都不稳定,不是标准壁面条件。

Q5. 下列哪些项会出现在烟雾密度场的演化中?

多选题 · mid

  • A.平流项← 正确答案
  • B.扩散项← 正确答案
  • C.重力项
  • D.源项← 正确答案

答案:ABD。烟雾密度场随速度平流、向低浓度扩散,并从火源/烟源注入新密度。重力通常作用于速度场的动量方程,不直接写在密度场演化里,所以 C 不选。

Q6. 火焰燃烧的反应速率随温度升高会呈现什么趋势?

单选题 · hard

  • A.线性下降
  • B.指数级上升← 正确答案
  • C.保持恒定
  • D.先升后降

答案:B。阿伦尼乌斯公式中温度在指数项分母上,温度升高会让指数因子迅速趋近 1,因此反应速率呈指数级上升。这也解释了火焰为何能突然猛烈燃烧,而不是缓慢渐进。

Q7. 体积渲染中,光线步进需要考虑哪些量?

多选题 · hard

  • A.吸收系数← 正确答案
  • B.透射率← 正确答案
  • C.燃料热值
  • D.颜色贡献← 正确答案

答案:ABD。光线穿过烟雾时,每个采样点有吸收系数 σ,可计算透射率 T,并累加该点的颜色贡献。燃料热值是燃烧模型中的量,决定放热多少,不是渲染阶段直接使用的量。

Q8. 使用稀疏体素网格的主要目的是什么?

单选题 · easy

  • A.减少活动体素数量← 正确答案
  • B.提高火焰颜色亮度
  • C.增加密度扩散速度
  • D.强制产生强烈湍流

答案:A。流体中真正有内容的格子只占少量,稀疏体素只存储这些活动格子,内存和计算量从全空间 O(N³) 降到 O(M)。火焰亮度、密度扩散和湍流强度都不由稀疏化直接决定。

Q9. 半拉格朗日平流的核心思路是什么?

单选题 · mid

  • A.向前追踪粒子路径
  • B.反向追踪采样点位置← 正确答案
  • C.随机扰动密度场值
  • D.压缩速度场存储量

答案:B。每个网格点反向追溯它上一时刻来自哪里,再取那里的物理量插值到当前点。这样能稳定处理平流,避免向前追踪的时间步稳定性限制。随机扰动和压缩存储都不是平流计算本身。

Q10. 实时流体优化常用的手段有哪些?

多选题 · hard

  • A.多分辨率网格划分← 正确答案
  • B.稀疏体素存储策略← 正确答案
  • C.禁止使用图形加速
  • D.小尺度湍流噪声贴图← 正确答案

答案:ABD。多分辨率在近处用细网格、远处用粗网格,稀疏体素只算活动格子,噪声贴图补充小尺度细节,三者都能在视觉损失很小的情况下提速。禁止 GPU 会大幅降低性能,与实时优化目标相反。