T.TAO
Back to Works
2024/graphics / rendering

真实感水体模拟

真实感水体模拟与渲染:基于 Phillips 谱的 FFT 海面、GPU 位置基流体(PBF),以及屏幕空间流体渲染。

TechnicalArtComputerGraphicsSimulation
真实感水体模拟

这个项目是对真实感水体模拟与渲染的系统性研究,是我与 Moussab Ibrahim、Weier Flora Xiao 合作为 CMU《视觉计算系统》课程撰写的论文。我们实现并对比了实时水体技术的几大主要流派——从程序化波形叠加到 FFT 海面频谱,从粒子流体到欧拉网格求解器——全部在 Unity 中用 compute shader 做了 GPU 加速。

完整论文内嵌在页面底部,下面是它所覆盖内容的导览。

表面波浪:从振荡器到 FFT 海面

正弦叠加与 Gerstner 波

最简单的水面是由正弦振荡器驱动的高度场。单个正弦波看起来明显是假的,但叠加不同频率、振幅和方向的多个波形,就已经能呈现出平静水面的样子:

h(x,t)=iAisin((kix)ωit+φi)h(\mathbf{x}, t) = \sum_i A_i \sin\big((\mathbf{k}_i \cdot \mathbf{x}) - \omega_i t + \varphi_i\big)

然而真实的波浪有尖锐的波峰和宽阔的波谷,纯正弦叠加做不到这一点。Gerstner 波通过让顶点同时做水平位移来解决——顶点在波峰处聚拢,形成经典的摆线轮廓,至今仍是海面着色的标准手法。

基于 Phillips 谱的统计海洋建模

任何有限的周期波叠加,从高处俯瞰终究会暴露出重复的平铺感。海洋学研究则把波高视为具有统计规律的随机变量。沿用 Tessendorf 的方法,我们在傅里叶空间中合成波高场:每个波矢 k\mathbf{k} 对应一个由高斯噪声采样的复振幅,其分布由 Phillips 谱塑形:

Ph(k)=Ae1/(kL)2k4k^w^2,L=V2gP_h(\mathbf{k}) = A \, \frac{e^{-1/(kL)^2}}{k^4} \, |\hat{\mathbf{k}} \cdot \hat{\mathbf{w}}|^2, \qquad L = \frac{V^2}{g}

其中编码了风速 VV 和风向 w^\hat{\mathbf{w}}——垂直于风向的波会被抑制,短波长尾部收敛性差的问题则用高斯因子 ek2l2e^{-k^2 l^2} 压制。

时间演化来自色散关系 ω2(k)=gk\omega^2(k) = gk:深水中不同波长的波以不同速度传播,这正是海面看起来"活"的原因:

h~(k,t)=h~0(k)eiω(k)t+h~0(k)eiω(k)t\tilde{h}(\mathbf{k}, t) = \tilde{h}_0(\mathbf{k}) e^{i\omega(k)t} + \tilde{h}_0^*(-\mathbf{k}) e^{-i\omega(k)t}

让它实时化的 FFT

每帧都要把频谱变换回空间高度场,意味着在 512×512 网格上做逆 DFT——O(N2)O(N^2) 完全不可行,O(NlogN)O(N \log N) 则绰绰有余。论文从第一性原理推导了 Cooley-Tukey FFT:复数作为旋转、欧拉公式、四点蝶形运算、旋转因子的对称性,以及分治的各个阶段如何组装成"先水平后垂直"的一维 FFT Pass,最终在 GPU 上生成高度图。

体积流体:粒子与网格

高度场无法飞溅。为了得到真正三维的流体行为,我们实现并对比了三种模拟范式,全部用 Unity compute shader 并行化。

位置基流体(PBF)

PBF 直接在位置上工作,绕开了基于力的 SPH 的刚性问题:先用速度和重力预测粒子位置,再迭代地把它们投影到不可压缩约束上:

Ci=ρiρ01=0C_i = \frac{\rho_i}{\rho_0} - 1 = 0

其中密度 ρi\rho_i 用 poly6 平滑核在邻居上估计,位置修正 Δpi\Delta \mathbf{p}_i 通过逐粒子的拉格朗日乘子分配。均匀网格邻居搜索(格子边长 = 交互半径,27 格查询)把邻居查询从 O(n2)O(n^2) 降到近似 O(n)O(n)——这是数万粒子能保持交互帧率的关键。

光滑粒子流体动力学(SPH)

Navier-Stokes 动量方程的经典力学形式:压力、粘性力和密度全部通过平滑核求值(密度用 poly6、压力用 spiky 梯度、粘性用拉普拉斯核)。借助 GPU indirect instancing,我们实时跑到了约一万个粒子。SPH 能漂亮地捕捉水滴和飞溅,但对时间步长和刚度参数极其敏感——这些"有教育意义的痛苦"正是我们转向 PBF 的动机。

欧拉网格求解器

相反的世界观:固定空间而不是粒子。速度和密度存在交错网格上;每步先做半拉格朗日平流,再用 Gauss-Seidel 压力投影强制 v=0\nabla \cdot \mathbf{v} = 0。在 GPU 上并行化 Gauss-Seidel 并不平凡,因为相邻格子共享边——我们采用棋盘分区把格子分成两个互不相交的组,让每半张网格并发更新而不产生竞态。网格方法明显比 SPH 稳定,规模也超过了一万格子。

屏幕空间流体渲染

粒子不是表面。为了把 PBF 模拟渲染成连续的水体,我们实现了屏幕空间流体渲染管线:

  1. 粒子球体——几何着色器把每个粒子展开成朝向相机的四边形,片段着色器丢弃球外像素。
  2. 深度 Pass——渲染粒子深度并编码供后续使用。
  3. 双边滤波模糊——在保留轮廓的同时平滑深度缓冲,把一颗颗粒子"熔"成连贯表面。
  4. 法线重建——从深度梯度经叉积重建视空间法线。
  5. 厚度 Pass——关闭深度测试的加法混合,度量每条视线穿过多少流体。
  6. 着色——漫反射 + 环境光 + 高光,用 Beer-Lambert 衰减 I=ekdI = e^{-kd} 做体积吸收,用 Schlick 近似计算 Fresnel 反射。

最终效果是一个透明、有折射感的液体体积——完全从粒子数据计算而来,没有任何网格化步骤。

这个项目展示了什么

  • 覆盖水体技术栈的广度——程序化波形、频谱海面合成、三种流体模拟范式、完整的屏幕空间渲染管线,全部亲手实现而非纸上综述。
  • 效果背后的数学——从零推导复分析与 FFT;理解每种频谱、色散关系和平滑核的适用边界。
  • GPU 工程判断力——compute shader 并行化、无竞态的 Gauss-Seidel、网格邻居加速,以及对 SPH、PBF 和欧拉方法在稳定性、细节与可扩展性之间的坦诚权衡分析。

完整的 13 页论文:

Realistic Water Simulation — 完整论文Open ↗