游戏水体表现之波浪动画:金波闪烁,浪花朵朵

2022-3-26 12:27成都雨航 1049 0

水,灵动清丽,令人神往遐思;水,又雄浑澎湃,充满了无限遐想。水面的光以及掠过的影子,惹人怜爱。游戏业界对于水体一般是使用贴图动画驱动细分表面,加上粒子动画来表现水的动态效果。如果想要达到更进一步的效果,使水波泛出秀色,则会使用表面交互模拟的一些方法,或进行三维空间中的模拟来增加水体的真实性。本文将对游戏中江、河、海、湖等大面积水体采用的波浪动画技术的原理和实现进行分享。

波浪动画

使用波浪动画的目的,是为了在游戏世界范围中,根据不同的视距来表现不同水体整体的流动感。因此,波浪动画需要使用廉价的计算去近似模拟出水的运动来骗过玩家。在此之上可以叠加一些美术效果和交互模拟来增加水体的表现和真实感。本文将会介绍三种波浪动画的算法,其中包括:Gerstner波、Statistical波和分型布朗运动。

Gerstner波

Gerstner波又叫Trochoidal(摆线)波,在游戏水体中是最基础的效果之一。理论上来说,Gerstner波是周期性表面重力波欧拉方程的精确解,描述了无限深度的不可压缩流体表面上的行进波[1]。Gerstner波在Sinusoids波的基础上增加了水平方向(X/Z)的偏移分量,因此可以模拟出波浪的陡度,它的方程如下:

其中

[公式]
[公式]
是提供控制波浪的波幅和陡度的值,
[公式]
[公式]
分别是各个波的方向和wave vector的大小。每个波浪的控制参数可以通过分开设置,也可以通过设定好参数范围和过渡曲线来随机生成。在表面顶点的基础上增加Gerstner波产生的偏移,可以让高频的波峰处聚集更多的顶点,模拟得到更好的波浪细节。波浪模拟不仅需要计算波的偏移,还需要计算波的斜率,它的方程如下:

最终得到可以得到如下的波浪效果:

Statistical波

Gerstner波的本质是正在各个轴体上不同频率的Sinusoids波的线性叠加。为了控制开销,如果直接在空域上进行实时计算注定不能循环求和过多次,因此得到的波浪比较简单。同时,使用过多的波也会大幅增加美术同学调整效果参数的负担。为了解决这个问题,可以使用模拟中常用的快速傅里叶变换(FFTs)这个数学工具,在频谱上计算各个频段的波的幅值,然后转换到空域中得到Statistical波模拟结果,即最后的波偏移。

1.Dispersion

[公式]

Statistical波与Gerstner波一样,存在一个频率和wave vector大小(这里记为

[公式]
)的关系,称其为Dispersion关系,它的方程如下:

而在实际工程中,通常会增加一个额外的SurfaceTensionScale(这里记为

[公式]
)项来来增加短波的抖动:

float CalcDispersionV2(float2 k, float surfaceTensionScale, float dt)
{
	float kLen  = length(k);
	float kLen2 = kLen * kLen;
	return sqrt(G * kLen * (1 + kLen2 * surfaceTensionScale * surfaceTensionScale)) * dt;
}

2. 频谱与快速傅里叶变换

Statistical波的傅里叶变换过程可以表示为离散傅里叶级数的形式:

其中

[公式]
[公式]
是模拟的分辨率,
[公式]
是模拟的空域覆盖范围。
[公式]
是每个傅里叶项的幅值,它决定了最后空域上
[公式]
的偏移。

float2 Getk(float n, float m, float len, float res)
{
	float2 nm = float2(n<=res/2?n:(n-res),m<=res/2?m:(m-res));
	return 2 * PI * nm / len;
}
[numthreads(8, 8, 1)]
void SpectrumDepth1(uint3 id : SV_DispatchThreadID)
{
	float n = id.x;
	float m = id.y;
	float2 k = Getk(n, m, _Length, _Resolution);
	float kLen = length(k);
	float IkLen = kLen <= FLT_EPS ? 0 : rcp(kLen);

	float phase = CalcDispersionV2(k, _SurfaceTensionScale, _AcculatedTime);
	float2 pv = float2(cos(phase), sin(phase));
	float2 hTildekt = ……;

	_TmpDst[id.xy] = float4(hTildekt, 0, 0);
}

3. 从菲利普斯频谱到初始频谱

根据论文

[公式]
中的描述,Jerry配合使用了菲利普斯频谱(分析半经验模型)和高斯随机数来计算初始频谱:

其中

[公式]
是由均值为0方差为1的高斯随机数生成器(Box-Muller transform)
[公式]
生成的高斯随机数,而源头的频谱模型则选用了适合于完全发达(fully developed,风浪占主导)海洋的模型:

其中

[公式]
代表风力向量,
[公式]
代表波浪的波幅。而通常在工程中
[公式]
,还会通过乘以下述的系数来抑制菲利普斯频谱中收敛性差的问题。实际表现为抑制Statistical波中的高频信息,把波变得模糊了。

得到初始频谱之后,可以根据Dispersion关系随即算出:

[公式]

在实际计算的过程中,要善用好

[公式]
的共轭关系,采样初始频谱的
[公式]
取共轭即可得到
[公式]
,可以减少RenderTarget的两个通道。对应的代码如下:

float2 hTilde0k = _Input[id.xy].xy;
float2 hTilde0MinuskConj = Conj(_Input[(int2(_Resolution.xx) - id.xy) % _Resolution].xy);
float2 hTildekt = MultComplex(hTilde0k, pv) + MultComplex(hTilde0MinuskConj, Conj(pv));

4. 汹涌度、斜率和雅可比

上述的从菲利普斯频谱到初始频谱,再到Dispersion关系,最后得到的空域信息仅仅是高度场。想要得到海水汹涌的效果则还需要类似Gerstner波一样的水平方向上的偏移向量,其频谱的计算方程如下:


[公式]
类似于Gerstner波的
[公式]
系数,由美术控制陡度大小。值得注意的是,作者在论文中给出的公式在
[公式]
前还乘以了
[公式]
,但经过实验是不取负才能得到正确的尖波。

在频谱上也能求导精确地计算出斜率向量地频谱,然后再通过FFTs变换到空域:

同样地雅可比行列式也能通过同样的方式变换出来:

计算的雅可比行列式可以通过一个Heaviside函数来估计出白沫的生成区域,即下图红圈标记的范围

[公式]

在工程中,使用了Complex2Complex FFT算法,经过初始频谱、Dispersion、FFT得到最后的空域结果:

由Complex2Complex FFT特性,仅需要两次变化就可以算出

[公式]

在算出空域上的波浪结果后可以得到developed海洋的运动状态:

分型布朗运动

Statistical波适合模拟波涛汹涌的海水,但对于江河等则需要额外的方法来模拟快速流动的效果,这里选择的是分形布朗运动(FBM)[5]。从原理上来说,FBM是在循环中叠加噪声,以一定的倍率(lacunarity)升高采样噪声的频率,同时以一定的比例(gain)降低噪声的波幅,可以得到具有自相似性的波形。伪代码如下:

for (int i = 0; i < octaves; i++) {
   y += amplitude * noise(frequency*x);
   frequency *= 2;
   amplitude *= 0.5;
}

FBM选择不同的噪声可以得到丰富的效果,例如使用3D Perlin Noise得到下图的波形:

而使用二维噪声贴图,根据视距远近计算出FBM循环次数(Mipmap的思路),配合Flowmap就可以得到湍流的效果:

总结

在水体的模拟中,波浪动画模拟是用来提供水整体的动态氛围的。而细节的动态则需要使用交互级别的算法,例如Wave Particle、Wave Packets、Surface Wavelet等,但随之也会带来更高的开销。设计一个高效的水体框架、权衡需求来选择算法达到效果是很重要的,而波浪动画模拟仅仅是水体表现的基础内容,希望这次分享能让大家对水体中波浪这部分的知识能有一个相对深入的理解。


参考文献

[1]Trochoidal wave. https://en.wikipedia.org/wiki/Trochoidal_wave

[2]Tessendorf J. Simulating ocean water[J]. Simulating nature: realistic and interactive techniques. SIGGRAPH, 2001, 1(2): 5.

[3]Box-Muller_transform. https://en.wikipedia.org/wiki/Box-Muller_transform

[4]The technical art of sea of thieves. https://dl.acm.org/doi/10.1145/3214745.3214820

[5]Water Rendering in Far Cry 5. https://www.youtube.com/watch?v=4oDtGnQNCx4


鲜花

握手

雷人

路过

鸡蛋

最新评论

QQ|手机版|小黑屋|九艺游戏动画论坛 ( 津ICP备2022000452号-1 )

GMT+8, 2024-3-29 17:57 , Processed in 0.091112 second(s), 17 queries .

Powered by Discuz! X3.4  © 2001-2017 Discuz Team.