计算着色器(Computer Shader)中可以使用线程组并行进行计算,很适合用来计算波浪(水面、地形等)的顶点数据。在学习完DirectX11 With Windows 计算着色器:波浪(水波)后,要求完成FTT 海面模拟,并且可以使用 imgui 调节参数控制波浪大小。
FFTWaves
在《【学习笔记】Unity 基于GPU FFT海洋的实现-理论篇》FFT函数:
其中,
参数 是我们水平方向的坐标, t 是时间,函数 h 可以直接给我们返回在时间 t 时,
处的海面高度。
被定义为
为波矢量,
和
是海平面的大小, N 和 M 是我们采样离散点的数量。当然 N 和 M取值越大我们得到的波形就更加细节(叠加的波就更多),当然计算时间也会大大的增加。
我们只需要计算出频谱然后按照 函数就可以得到我们海面的高度,现在我们来看一下频谱公式
g 是引力常数
和
是两个相互独立服从均值为0,标准差为1的高斯随机数。
是我们的方向波谱,方向波谱一般描述为
,这和我们前面的参数不太一样,其实他们之间可以相互转换,有兴趣可以看Empirical Directional Wave Spectra for Computer Graphics这篇论文。
方向波谱是非定向波普
和方向拓展函数
的乘积
W 是我们前面提到的角频率, 是波矢量相对于风向的角度
在Simulating Ocean Water-Jerry Tessendorf 中使用到的非定向波谱为 ,而方向拓展函数为
,他们的乘积就是
在我们的实现中风向拓展函数使用的不是 ,而是Donelan-Banner定向传播,这里就先不贴这个公式了,免得 显得公式太多....
以上FFT海面高度的公式,接下来是水平偏移
可以看到这和我们的高度函数基本一样,只是我们需要把频谱进行改变一下。这是对 X 和 Z 总体的描述,我们将其拆开就可以得到对 X 和 Z 单独的描述
中间的其实就是两个复数相乘。
HLSL
在上一部分了解到,我们需要获得每个波的角频率w、波长k、海平面的大小L.x、L.y、高斯随机数、风向的角度
和系统的时间t。此外,为了在计算着色器中计算imgui ,我们还需要知道列线程组的数目。知道了需要,我们就可以在FFT
Waves.hlsli
中定义结构体:
struct FFTWave
{
float g_WaveW; // 角频率
float g_WaveK; // 波长
float g_WaveX; // 海平面的大小
float g_WaveY; // 海平面的大小
float g_WaveR; //高斯随机数
float g_WaveI;