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