GPU-Driven 水体渲染
一、效果展示
1.1 静帧效果
-
目前渲染效果:

-
初版效果:

1.2 动态效果
二、技术拆解
2.1 几何阶段
初版方案
- 波形:分形噪声(FBM)
目前版本方案
- 波形:Gerstner 波
- 交互:波动方程
- 波动方程原理实现 + 历史帧俯视角深度 Mask 对比区分动态静态物体 + 像素对齐 + 帧同步(保证固定时间长度迭代一次):

- 波动方程原理实现 + 历史帧俯视角深度 Mask 对比区分动态静态物体 + 像素对齐 + 帧同步(保证固定时间长度迭代一次):
2.2 着色阶段
- 基本表面着色:自写基础 PBR
- 折射:分形噪声或 Gerstner 波扰动
OpaqueTexture - 间接光反射:SSPR(屏幕空间平面反射)→ 更新为双面 SSPR,以作为水下全反射效果:

- 通透感表现:盗贼之海 SSS 方案 + 深度 Lerp → 盗贼之海 SSS 方案 + 可美术自定义化的深度颜色与可见度 Lerp(水下效果与水面着色兼顾):

- 焦散 (Caustics):
- 初版:基于屏幕空间的光子映射法
- 目前版本:
- 反射焦散:基于屏幕空间的 Gather 方法
- 折射焦散:根据 Shadowmap 的特性进行
CausticCascadeMap级联写入 + Light-NDC 空间的 RayMarching + 世界空间印花:

- 白沫 (Foam):基于 JFA (Jump Flooding Algorithm) 生成 SDF → 根据 Gerstner 波求得雅可比行列式(预备海面渲染)
- 近水线侵蚀:屏幕空间检测近水范围 + 修改
OpaqueColor色相饱和度明度:
- 水线 (Waterline):根据摄像机近平面世界坐标与水面解析得到的世界坐标得到距离场 + Kawase 模糊
Capture_Opaque_Color+ 明度降低:
- 水下体积光:根据折射焦散 Pass 得到的 RT 做屏幕空间光线步进采样该 RT +
WaterlineMaskRT:
2.3 网格阶段
初版方案
- 自适应曲面细分:自写基于距离的 Quad 曲面细分
目前版本方案
- GPU-Driven 方案:
- Renderer Feature 驱动四叉树迭代法求原始面片 Size + Position
- 基于曲面细分着色器的
fractional_even四叉树细分逻辑 - 视锥剔除(Frustum Culling):

三、引擎具体实现展示
3.1 GPU-Driven 架构
MaterialDataBuffer→ 逐 Material Profile(OS)→Buffer.setDataSubDivideQuadDataBuffer(Pos / Size / MaterialID)→ CPU 初步视锥体粗粒度剔除 →Buffer.setData→ GPU-SubDivideRendererFeature 迭代(切分逻辑函数 + 更新ArgumentBuffer)→DrawInstanceIndirect(根据 InstanceID 拿到必备信息)→ 曲面细分着色器(切分逻辑函数)→ 保证不发生不平滑穿插现象:
3.2 类 CascadeMap 解决 Gerstner 波重复解析与波动方程模拟 RT 重复采样消耗
- 问题背景:在吃水线效果、焦散(折射 + 反射)实现、水面顶点位移、视锥剔除逻辑、水面本体渲染中,都需要重复求解解析式,极大占用 ALU 算力。
- 解决方案:以空间换时间的思路预计算 Gerstner 波的信息(法线、位移、挤压度):

- 折射焦散基于 Nsight Graphics 的优化前后性能对比:
(结论:就折射焦散而言,已有显著的性能提升)
3.3 Renderer Features 管线配置
- 分别实现距离场、环境反射、焦散(旧版):

- (目前版本):

3.4 Shader 参数面板
- 旧版 Shader 面板:

- 新版 Shader 面板:

四、部分效果个人思考过程与问题
4.1 旧版思考
- 水面顶点动画: 根据距离动态细分的 Quad 曲面细分着色器 —— 本人发现 Tri 曲面细分的距离动态细分过程不够平滑,故尝试使用 Quad 规则进行细分,并编写距离动态细分规则,较 Unity 内置的动态距离细分函数更平滑。
- 焦散: 在尝试了通过 Light 空间的光子映射法实现焦散后,本人发现焦散的生成可以直接调用 Unity 的级联 Shadowmap 来实现类级联焦散。后对于焦散的耗能问题,尝试实现 ScreenSpace 的焦散;不过 ScreenSpace 的焦散仅在正午有较好效果(屏幕外的信息缺失),但性能较好,特定场景下可针对性使用。
- 白沫: 深度差白沫有一定的局限性:视角变化会导致白沫区域变化产生违和感。故通过 JFA 算法建立实时 SDF 场。
4.2 目前版本思考
- 曲面细分 + 切分的平滑过渡:
在选择
fractional_even和fractional_odd的细分模式过程中,前者的偶数细分特征十分适配切分四叉树的规则。这里可将fractional_even模式描述为:- 细分因子值为 :拓扑结构不变;
- :生成新的点与线段但保持位置不变;
- :平滑到对称位置。 故我们在设计切分细分函数时,只需要相邻边切分(细分)返回值的比值关系 ,并且避免极端情况(面片各边缘的切分逻辑返回结果过于迥异)导致的相邻边切分状态跳变。
- 视锥剔除的动态情况解决: FBM 与 Gerstner 波的核心区别:有无水平(XZ)的位移。故我们在做 Subdivide 与视锥剔除时(同时进行提升性能,省去了后续迭代的复杂度),需要应用 Gerstner 的位移信息以解决视锥边缘误剔除的问题。
- 目前版本架构问题与解决思路:
- 无法完美适配各种形状的水面 → 采用绘制 Lookup Watermap 的方法解决;
- 遮挡剔除(Occlusion Culling)对于目前的架构是可以实现的。