星鸿阁

 找回密码
 立即注册
搜索
热搜: 活动 交友 动画
查看: 780|回复: 0

游戏中的水体模拟技术

[复制链接]

2254

主题

2764

帖子

9644

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9644
发表于 2022-5-4 21:38:09 | 显示全部楼层 |阅读模式
游戏中的实时水体模拟技术file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/5f03f9f7da20d12fa2eb1d5021f55657_xs.jpgFOXhunt                             ·         10 天前      
     写在前面

海洋,溪流,湖泊等水体的模拟在游戏中是十分常见的技术,每个开发人员或多或少都听说过几种制作水体的方法。不过想要把水体模拟做好,做出高质量,其中还是有很多值得注意的地方。这篇文章就是总结一下个人制作水体模拟的心得,以及一些平时阅读技术论文和开发中容易忽略的细节。
首先要说一下,游戏中使用的“水体模拟”技术并不是真正的流体动力学计算,出于运行效率的考量,实际上使用技术的大多是用数学公式复现水体的视觉效果。从这点来说下面提到的公式基本都很简单,而且也不是金科玉律,可以根据每个人的理解进行改写。
游戏中使用的水体模拟技术大体可以分为三类

第一类是叠加不同的随机周期函数构成水体表面,多用来表现波涛起伏海面,暂且称为波形叠加法。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-9307f6ffdb83b341285ea59e1320c626_b.png第二类是使用波动方程或者近似公式来表现局部的水波,多用于表现物体与水面互动产生的涟漪。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-93ea89710c4b0bf745398ffbec0a944b_b.jpg第三类是使用预渲染的Flow Map表现复杂的水流运动,多用于模拟涡流等难于实时计算的非线性运动。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-90cd8d62406c45499e238ba1262be3d9_b.png第一部分 波形叠加
Gerstner波
波形叠加故名思义就是将很多个不同周期,不同振幅的周期函数叠加在一起。但在水体模拟中我们使用的基础波形并不是正弦和余弦波,而是一种叫做Gerstner波的特殊波形。Gerstner波和余弦波的差别,用一幅简单的图就能说明了。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-087b90d1c91aeaaecd4c74cfe54f7bcc_b.png与红色的余弦波相比Gerstner波在两侧有收紧的趋势,和真实海洋表面更加接近。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-47e566ec44b1518c1254bd2b66a91ec1_b.jpg真实海洋中比较尖锐的波形
Gerstner波构造起来非常容易,用2d的波形作说明,只要在y轴上取cos(t),再在x轴上添加一个相对应的sin(2t)位移就能得到。Gerstner波的"收紧"部分就是绿色箭头所指的sin(2t)。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-2399932ea7089cc9dc94e824413d7017_b.png斜切波形
Gerstner波还有一种很多人不知道的变换,就是斜切波形。大家一定知道cos(x)如果把x换成x^i,波形会向一个方向倾斜。图中的波形是cos(2*pi*x^2),可以看出波形明显向右边“倾斜”。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-618a98235d954a6867b5dee787f3e527_b.pngfile:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-236b93b89b3376dc813ff42e921e3cf7_b.png如果Gerstner的x和y坐标都加上这种倾斜,就能得到斜切Gerstner波,用来模拟涌向海岸边的潮水。
将很多个不同波长,不同振幅的Gerstner波叠加在一起,加上一些随机值,就能得到下图这种看起来很复杂的海面效果。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-9937a8a7fbfcb376ee0018f910f6fcd9_b.jpg
FFT叠加
如果需要更为复杂的波形叠加,可以使用逆向fft算法。因为fft的效率还不错,一幅512x512的频谱图对应262144个波形,同时叠加这么多波形,能给海面带来非常高的复杂度。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-760ae80663aeb2ef0df7f7847691877f_b.pngfft频谱图和叠加出来的位移图
计算白浪
这里再补充一个一般人不太知道的技术。用雅可比绝对值计算白浪出现的位置。
白浪是水面激烈碰撞涌起的白色泡沫。在水面模拟的时候可以认为在Gerstner波最尖锐的部分会产生白浪。这个尖锐的部分可以用雅可比绝对值来计算。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-0776e5f1a35b6c1c9c211ff3cad6f76b_b.png可以设定一个阀值,当雅可比绝对值小余阀值的时候产生白浪。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-19e334e060e521e315e3496a64d415b6_b.png我们制作的实时海面白浪,看起来还算自然
第二部分 波动方程
我想学理科的同学一定对波动方程不会陌生的。估计写的第一个matlab程序十之八九都是波动方程。实在不知道请查查wiki百科。这里不写一堆推倒公式了,免得大家看得头痛。
https://zh.wikipedia.org/wiki/%E6%B3%A2%E5%8A%A8%E6%96%B9%E7%A8%8B
https://zh.wikipedia.org/wiki/File:Wave_equation_1D_fixed_endpoints.gif
这里讲一个波动方程的变形wave particles。
这是07年的一片siggraph论文,虽然老了点,但效果很好。神秘海域4的水面模拟就是用的这个技术。
Wave Particles
wave particles的想法其实很直接。作者认为波动方程太简单了,波动方程的波之间不会相互影响 ,只会在碰到边界的时候反弹一下。那干脆别算波动方程了,把波都看成一个粒子,遇到边界会反弹,在移动的时候能量会衰减。再按照Gerstner波的样子变形出来,就是一个小鼓包。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-87ed1626585feade98fe7fc6d9b4bc9b_b.png如果你要制造一个扇面形状的波,发射一扇小鼓包。如果想制造一圈的波纹,就发射一圈小鼓包,随便你。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-1dca719925f466b718dd9f85cc738ee3_b.png但是随着小鼓包的移动,他们本来是团结在一起的,却渐渐散开了。这也好办,小鼓包可以随着移动而增殖,如果跑的距离太远了,就一个变三个。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-8bb772b7c1f7bfaa488c217780b37694_b.png到这里就可以看出wave particles的最大优点是直观易懂,容易控制,想要生成什么样的波纹都可以控制。这也是神秘海域4开发时使用这个技术的主要原因。
不过wave particles对于开发人员来说还是挺有难度的,尤其是作者在论文中很多细节地方都没写清楚,我在做的时候遇到了不少麻烦。这里就随便提两点吧。
第一是上面提到的斜切波形的问题,论文中能实现出漂亮的浪头形状。但文章中只用了普通的Gerstner波。基本不可能做出来这种效果。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-08e89f656f0b404f98f5fddbab75a1c1_b.png另一个问题是怎么把粒子渲染成位移图,文章中根本就没提。只提到以每个粒子为中心,渲染出一个Gerstner波形状。难道要每个粒子都向位移图渲染一个圆的范围吗,这个大的计算量怎么可能做到实时啊。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-ac3e129478931577a34e2ea8c03871a6_b.png实际的做法是先渲染出粒子的位置,然后分别在x方向和y方向做一次模糊filter,filter的核就是Gerstner波的公式,这样比起双向filter的消耗还要小,真是个值得记住的小技巧。
当然wave particles比起波动方程还是有局限性的,比如像From Dust那种上帝游戏,会增加和减少水量,还是用波动方程计算水的流动比较容易。
file:///I:/%E6%B0%B4%E4%BD%93%E6%8A%80%E6%9C%AF/%E6%B8%B8%E6%88%8F%E4%B8%AD%E7%9A%84%E5%AE%9E%E6%97%B6%E6%B0%B4%E4%BD%93%E6%A8%A1%E6%8B%9F%E6%8A%80%E6%9C%AF%20-%20Math%20Eye%20Candy%20-%20%E7%9F%A5%E4%B9%8E%E4%B8%93%E6%A0%8F_files/v2-03fff6139e9be3c697aa2d6c4c26bc22_b.jpg
第三类用Flow Map模拟水体比较偏美术,所以变种非常多,不太好讲。等以后有机会再说吧。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|starfluidga

GMT+8, 2025-5-7 12:35 , Processed in 0.015422 second(s), 20 queries .

Made by Liga 星鸿阁

Copyright © 2020-2048, LigaStudio.

快速回复 返回顶部 返回列表