水波模拟算法

一、理论依据

水波的物理学模型便是理论依据。水波有如下特性:

扩散:水波总是从被扰动的中心向外扩散。在水波扩散过程中每个点都在得到能量后以自己为中心震动,并向四周传播能量。之所以从干扰点向外扩散,是因为内部的各点能量互相抵消而看不到震荡。重要的是,每个点都在以自己为中心进行震荡,并向四周扩散能量。

衰减:水波在传播过程中能量会逐渐的衰减,因为水的震荡是有阻尼的。

折射:由于水波表面各处有不同程度的倾斜,由于折射,将会看到水底景物的不同程度的偏移,看起来是变形的。观察点正下方的景物由于折射偏移,开起来并不在正下方。

反射:由于水波表面的凹凸不平,比起平静时期的水面,水面上各点反光程度将会不同程度的受到影响,从而改变了自己的亮度,颜色。

水波还有衍射等特性。但是考虑问题的核心在于能量传递或者能量扩散。因为这是该模型的根源。

二、约束条件

实现该算法的约束条件。

约束条件

描述

实时渲染

由于该算法要实时渲染水波,所以只能近似推导,而且不能使用三角函数、除法等低效运算,以保证速度。

三、设计方案

用两个数组来模拟水池。数组大小:水池高度 * 水池宽度。其中一个数组存储水池的上一个状态,另一个用来存储当前用上一个状态正在计算的下一个状态。计算完毕,把新状态渲染出来;然后新的状态就变为“上一个状态”的水池,用它来计算更新的水池状态,数据保存在原来的第一个水池中。两个水池交替的成为新、旧状态池。从而,虽着实间的推移,能量就会被扩散开来。

为了保证执行效率,水波的扩散、折射等均用简化后的模型代替,以使算法成为线性简单的;对于里面的乘法、除法运算尽量采用2的幂,可以通过移位运算快速实现。

四、数学推理与算法设计

根据以上设计,就可以建立模型进行数学推理和算法设计。

上述两个矩形代表了两个数组,即两个水池状态。令水池宽度为W(W=w+1),水池高度为H(H=h+1),假设点A的坐标为(I,J),那么A点对应的数组下标为:(J * W)+ I 。 O点(0,0)对应buf[0],对角线B(w, h)代表buf[W * H – 1],即数组的最后一个元素。

计算波幅的公式推导:

如图所示,假设任意一点x0处下一个时刻的能量能根据当前状态下周围的12个点和x0自身的振幅推算出来。即x0在下一个时刻的振幅要由自身的当前振幅和受周围12个点的能量扩散得到。并且假设这12个点影响x0的程度都一样,这个模型已经得到很大的简化。可以得到:

x0’ = a * ( x1 + x2 + x3 + … + x9 + y1 + y2 + y3 + y4 ) + b * x0

a, b为待定系数,x0’为下一个时刻的振幅,其余为当前振幅。

如果假设水的阻尼系数为0,那么能量会守恒。即,所有点的能量总和在前后时刻的状态下保持不变。x0’ + x1’ + … + xn’ = x0 + x1 + … + xn

因为x0受周围12个点的影响,反过来也就是说周围12个点x1, x2, …. y4都要受x0的影响,x0总共要出现12次,其余都一样(忽略边缘)。

那么 ( 12a + b) * x0 + (12a + b) * x1 + ….. + (12a + b) * xn = x0 + x1 + … + xn

推导出:12a + b = 1的结果。

找出一个解: a = 1/4,b = -2,这样1/4可以移位得到,效率很高。

所以得到需要的数学公式:x0’ = (x1 + x2 + … + y4) / 4 – 2 * x0

但是实际上这组解不准确,测试中也出现了问题。因为按照事实,x0点本身对下一个时刻的能量影响不可能大于x0本身,只能等于它本身。所以,只能取b = -1,绝对值为1。这样,得到a = 1/6,

即x0’ = (x1 + x2 + … + y4) /6 – x0

经过测试,这组解效果最好,说明跟实际情况接近。

考虑阻尼:

真正的水是有阻尼的,否则,上面的模型产生的震动将永远进行下去。所以需要考虑一个阻尼,让每个点在后续的时刻能量比理想值有所衰减。

即x0’ = (x1 + x2 + … + y4) /6 – x0 然后有 x0’ = x0 – x0 * 阻尼因子

考虑折射:

要进行精确的计算不现实,因为当前的设计方案无法模拟真正的折射。现在进行线性逼近模拟就可以了。水面越倾斜,折射越厉害,即水下的景物看上去偏移越厉害。所以,用谋点的前后两点的波幅差作为该点的折射偏移量。

对于点x0来说,在x和y两个方向的折射偏移量分别为:

xoff = x7 – x5

yoff = x3 – x1

假设x0点的坐标为(I,J),那么x0点上应该显示的水底景物为 (I + x0ff, J + yoff)位置正下方的景物点。

考虑波源:

为了比较逼真的模拟波源,考虑水面受到扰动的时候并不是一个点上受到了扰动,而是在一个比较小的范围内受到了扰动。所以考虑一个扰动半径R,如果x0点上被扰动,那么以x0为圆心,半径为R的区域内的点都会不同程度的获得能量进行震动。这个能量从圆心向外衰减,即x0点获得最大的能量,距 x0越远的点获得越少的能量。

现在根据下面的图示来进行数学推导近似,以获得比较逼真的扰动效果。

假设,圆心为A,距离为d的B点(d < R)获得的能量为:

Eb = Ea – Ea * (R – d) / R = Ea * (1 – d / R)

上面这个简单的近似公式经过测试,能逼真的模拟波源。

考虑光反射:

考虑实际情况,如果水面上出现水波,那么由于水面的凹凸不平,各点对光的反射与平静的水面相比将会发生不同程度的变化。具体与很多因素有关,不可能进行精确的计算。与前面一样,这里用简单化的模型进行线性近似计算。

对于水面上一点x0(I,J),对应到数组buf[J*w + I],该点的能量假定为E0,那么x0点上显示的景物点取得以后,得到颜色分量 r,g,b

现在考虑反射后得到新的颜色分量:

r = r + E0 g = g + E0 b = b + E0

如果超出0—255的范围,则进行修正。这样就得到一个效果,就是根据能量的不同,水面上有些点的亮度得到加强,而有些点的亮度得到削弱,由于能量按照波形分布,最终得到水波的波形效果。

(注:这里的反射只考虑了亮度变化,而没有考虑由于环境光而产生的颜色变化)

五、验证

在使用了背景图片的情况下,水的折射就可以单独成波,没有考虑反射也能看到效果。因为背景图像按照波能偏移显示,得到水波效果。

在考虑了反射的情况下(无论是否考虑了折射),不论是否使用了背景图像,都会有水波效果,因为水面各点的亮度按照波能进行加强和减弱。当然,两者考虑的情况下水波最为逼真。

这就相当于对一池清水,没有反射光的时候就算有扰动,也看不到波形;而如果有水底背景,只要有折射存在,也能感到有水波存在。形成水波最主要的还是反射因素。

声明:本文系网络转载,版权归原作者所有。如涉及版权,请联系删除!

原文发布于微信公众号 - 智能算法(AI_Algorithm)

原文发表时间:2017-02-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

细数20世纪最伟大的10大算法

[1946: John von Neumann, Stan Ulam, and Nick Metropolis, all at the Los Alamos S...

1071
来自专栏龙行天下CSIEM

科学瞎想系列之五十 场是个神马鬼

无论你信与不信,它无时无刻不存在着; 无论你用与不用,它无时无刻不作用着; 无论你懂与不懂,它无时无刻不影响着。 ...

3054
来自专栏机器之心

资源 | Richard Sutton经典教材《强化学习》第二版公布(附PDF下载)

2818
来自专栏量子位

如何用卷积神经网络从歌曲中提取纯人声?这里有教程+代码

安妮 编译整理自 Madebyollin博客 量子位 报道 | 公众号 QbitAI 你应该对阿卡贝拉(Acapella)不陌生吧。这种无伴奏合唱的纯音乐起源于...

4917
来自专栏Android群英传

贝塞尔Loading——化学风暴

731
来自专栏算法channel

Kaggle最受欢迎的10个竞赛数据集

最近有人问有没有相关数据集,这几天抽时间整理了以下数据集,标题即是Kaggle竞赛题目,可以直接搜索获得赛题详细介绍,在此列出10个参赛队伍最多的竞赛题及标签...

4.4K12
来自专栏华章科技

一位数学专业女生大学毕业前的感慨:不好意思,是我天真了

问自己永远有多远!!!! 已知X是非平方数,证明X开根号是无理数 TM这还需要证明 学完定与不定积分后

751
来自专栏Python中文社区

摩根纽约总部量化女神手把手教你学Python机器学习与量化交易

“量化投资”是指投资者使用数理分析、计算机编程技术、金融工程建模等方式,通过对样本数据进行集中比对处理,找到数据之间的关系,制定量化策略,并使用编写的软件程序来...

6240
来自专栏生信宝典

扩增子图表解读1箱线图:Alpha多样性,老板再也不操心的我文献阅读了

作者: 刘永鑫 日期:2017-6-17 阅读时长:10 min 宏基因组学 宏基因组学目前的主要研究方法包括:16S/ITS/18S扩增子、宏基因组、宏转录...

3566
来自专栏数据魔术师

干货|迭代局部搜索算法(Iterated local search)探幽(附C++代码及注释)

6785

扫码关注云+社区

领取腾讯云代金券