海洋和天空渲染
同一片海面,用可控波组和统计频谱会得到两种完全不同的工作方式。
项目概况
- 引擎
- Unity / Unreal Engine
- 着色语言
- HLSL
- 近景海面
- 多组 Gerstner 波,位移函数偏导给出法线
- 远海方案
- FFT 频谱推进相位,逆 FFT 还原网格位移
- 体积云
- Ray Marching,按云层包围体求有效步进区间
UnityUnreal EngineHLSLFFTRay Marching
Unity 体积云与 Gerstner 海面
体积云沿观察方向采样三维密度场,并在每一步更新透射率。低频噪声决定云团的大轮廓,高频噪声只负责侵蚀边缘。一个容易浪费性能的做法是让空区域也使用相同步数;这里先用云层包围体求出有效步进区间,离开云层后立即结束积分。
近景海面叠加多组 Gerstner 波。普通正弦波只上下移动顶点,轮廓看起来像一张橡胶布;Gerstner 波还会沿传播方向水平推挤顶点,让波峰自然聚拢。位移函数的偏导同时给出切线和副切线,法线会跟随真实波形变化。天空、太阳方向和反射采样共享同一套时间参数,海面不会和云层各走各的。
P' = P + QAD cos φ, y' = y + A sin φD 是水平传播方向,A 是振幅,Q 控制尖锐度。水平位移是波峰能聚起来的原因。
φ = k(D · x) - ωt每组波使用不同方向、波长和相位。少量可控波组适合近景构图,也方便美术直接调形。
T(s) = exp[-∫₀ˢ σtρ(u)du]密度 ρ 越高,透射率下降越快。步进时若 T 已经接近 0,可以提前退出,省下后面的采样。
Unreal FFT 海洋频谱
手调 Gerstner 波很适合控制镜头附近的形状,但波组一多,方向、尺度和相位很快就难以维护。FFT 海洋把问题换到频域:先按波数分配能量和主风向,再更新每个频率分量的复数相位,最后通过逆 FFT 还原空间位移。长浪、碎波和方向扩散可以来自同一份频谱,不需要堆几十条独立正弦。
这不是把 Unity 场景原样搬到 Unreal,而是一次模型选择实验。近景需要可控轮廓时,我会优先用 Gerstner;画面要覆盖大范围远海时,频谱方法更自然。两者的取舍取决于镜头和调参方式,不是简单的画质高低。
h̃(k,t) = h₀(k)eⁱωᵗ + h₀*(-k)e⁻ⁱωᵗ初始频谱决定各个波数的能量。时间只推进复数相位,因此波形会连续演化。
h(x,t) = Σk h̃(k,t)eⁱᵏ·ˣ逆 FFT 把频域分量一次还原成网格高度。斜率与水平位移也能从同一频谱派生。