3D模拟海洋是一个比较复杂的工程,大体分为:海洋动画,水面光照,水下光照以及其他的效果。这其中海洋动画是最为复杂的,除需要比较真实的控制顶点的运动以外,为保证其实时性还需要把地形lod和tess等技术融合进去。冰冻三尺非一日之寒(- -),这里暂时先模拟海洋动画,其它的内容以后逐步完善。
海洋动画:
这就是一个完整的海洋动画顶点更新的过程,其中H0为起始位置,最后3张纹理:Diplacement,Folding,Normal 是我们用来更新顶点位置的结果。
1.H0 :
H0的两个重要组成部分是:菲利普斯函数 + 高斯随机数函数。这里的k是顶点的(x,z)坐标,从控制的角度来讲,这里面最重要的还是菲利普斯方程:
L:L = (V*V)/g 其中 V 为风速(标量) g 为重力加速度
w(omega) :风的方向向量,是一个单位向量
A:是波幅
float phillipsSpectrum(float2 k) //Ph(k)
{
float wave_amplitude = param0.z;//3.0f;
float dirDepend = param0.w;//1.0f;
float2 windSpeed = param1.xy;//float2(0.8f, 0.6f) * 6.0f;
float v = sqrt(windSpeed); // 计算向量长度
float2 windDir = windSpeed/v; // 风速的模即是风向
// L = V^2 /g V:windSpeed g:GRAVITY
float l = dot(windSpeed, windSpeed) / GRAVITY;
float w = l / 1000.0f;
float kDot = dot(k, k); // k*k
float kDotW = dot(k, windDir); // k*windDir
//A * (exp(-1/(kL)^2)/k^4) * (dot(k,w))^2 * exp(-k^2 * l^2)
//Amplitude * expf(-1 / (ksqr * L * L)) / (ksqr * ksqr) * (dot * dot);
float phillips = wave_amplitude * exp(-1 / (l * l * kDot)) / (kDot * kDot * kDot) * (kDotW * kDotW);
// 筛选出波移动相反的风
if (kDotW < 0.00001f)
{
phillips *= dirDepend;
}
return phillips * exp(-kDot * w * w);
}
2.H0 -> Ht :
Ht要计算X,Y,Z三个维度的位置,为啥X和Z的也要计算呢?因为海面上的每个点都相当于在做一个绕圆运动
每个顶点都是以风向为方向,绕一个圆做环形运动,所以,除了上下有位移,X和Y也有位移。具体的H0和Ht之间的关系在第一张大图上面有,我自己也是模仿别人的实现做的,对方程的理解并不深。
H0 -> Ht 的阶段结果:
这个是在CS里面算出来的H0,其中把高斯随机数放到一个纹理里面传进来的
这个是Ht,也是在CS里面算的,可惜啊。到了这一步就犯晕了,不知道实数和虚数之间的关系,已经在后面的FFT如何处理。
3.IFFT阶段:为啥需要使用傅里叶转换呢?因为菲利普斯所得到的结果是基于频域的,我们得把它转换到时域。这个阶段,最初是想尝试自己用hlsl在CS里面实现的,但是,在实现的时候有几个地方理解不了,最后参考N卡上面的例子实现的。
阶段结果:Displacement
阶段结果:Gradient