APP下载

基于Perlin噪声的海浪三维仿真研究

2023-01-05张国栋朱长德熊桂芳

河南科技 2022年24期
关键词:见式插值海浪

张国栋 王 波 朱长德 熊桂芳 郭 澍

(1.南京信息工程大学遥感与测绘工程学院,江苏 南京 210044;2.航天远景科技(南京)有限公司,江苏 南京 210046)

0 引言

“数字海洋”是由“数字地球”衍生而来的,构建“数字海洋”基础信息框架是我国重大海洋计划之一。近年来,随着地理信息科学、遥感(Remote Sensing,RS)、计算机技术、虚拟现实(Virtual Reality,VR)的快速发展,数字海洋已无法满足国家日益增长的需求。“三维海洋”的发展与完善是“数字海洋”的最高目标,对我国海洋科学研究、海洋国防安全、海洋资源管理、海洋信息服务和海洋决策支持等具有非常重要的意义。海浪作为海洋的“头发”,其重要性不言而喻,海浪模拟是一个复杂的过程,且与计算机技术息息相关。目前,各国学者对海浪的研究建模方法可分为基于流体力学的建模方法、基于海浪谱的建模方法、基于几何模型的建模方法、基于动力模型的建模方法、基于分形的建模方法[1]。柏林噪声(Perlin Noise)建模方法生成的视觉元素看起来更自然,是基于几何模型使用频率较高的一种方法。1983年,Perlin[2]因不满当时计算机产生不自然的纹理效果,首次提出Perlin噪声,并于1985年在SINGGRPH上公开发表该算法,凭此获得了奥斯卡科技成果奖。随后该方法被用于构造海浪高度场。Johanson[3]通过引入投影网格的概念,在后空间构造海面网格,并通过叠加Perlin噪声来构造海面高度场。宋歌等[4]使用Perlin噪声扰动的方式来模拟实现视点远处的海洋运动。

Unity是一个由Unity Technologies研发的、让用户方便快捷地创建三维视频游戏、建筑可视化、实时三维动画、创建三维地形等多平台的综合性开发游戏平台。Unity不仅能在Windows、Linux、MacOS等主流平台上运行,还可将其开发的产品发布到Windows、WebGL、Android等平台 上,Unity Web Player插件也支持发布网页游戏及网页浏览,是一个全面且功能强大的专业引擎。Robert[5]使用Unity平台来模拟海岸环境的空间和位置。王怀兵等[6]使用Unity自带的粒子系统进行船行波的三维仿真试验。刘雪梅等[7]提出利用Perlin噪声构造分形,网格顶点采用位移映射算法,在Unity3D中生成地形。欧阳劲夫等[8]使用Unity3D引擎来模拟光的反射和折射,利用可视化编程插件来制作水面水体着色器,从而实现对水面波浪的模拟,该方法虽实现了低性能耗损,但也存在生成的水体细节表现不足等问题。综上所述,本研究在Unity3D平台中,通过创建海面网格,然后使用Perlin噪声生成海面高度场,使用高次插值函数对生成的高度场进行平滑拟合,解决由海浪波峰过于尖锐导致的失真问题,在光影效果上使用Shader Graph渲染管线,采用菲涅尔效应进行线性插值,来生成海面颜色,然后通过法线进行贴图,生成真实状态的海洋场景。

1 海浪生成

海浪的生成先通过三维Perlin噪声进行叠加来产生分形Perlin噪声,将产生的高度场映射到海面网格,然后添加波面纹理和光照,从而生成海浪模型。主要包括海面网格的构建、生成高度场、渲染纹理。

1.1 海面网格

Unity创建的海面网格方便快捷,可分为以下三个步骤。

1.1.1 网格基础组件。先打开Unity3D软件,在Hierarchy中创建一个空物体(Game Object),并将其重命名为Perlin Waves。在inspector的Add Component中添加Mesh Renderer组件,该组件可对生成的网格模型进行渲染。创建完Game Object后,在project中创建C#脚本,脚本名要与创建的物体名相同,否则运行时会出现错误。

1.1.2 网格属性。打开刚创建的C#文件,定义海面网格所需的变量,即海面宽度x、海面长度z、海面网格的分辨率Di mens ions。Unity坐标系采用左手坐标系,即用左手食指和大拇指摆出“L”的手势,且食指向上,大拇指指右,然后伸出中指,此时中指会指向正前方。大拇指、食指、中指分别对应x、y、z轴的正方向,即海面网格的长和宽用z和x表示。

1.1.3 计算网格。由1.1.2中定义的变量来计算网格的点(verts)、UV值(uvs)及三角形(tries)。网格的点是用来计算生成的三角形,UV值是u、v纹理贴图坐标的简称,其定义了图片上每个点的位置信息,三角形显然就是用来形成海面网格的。其中,各个值的计算方法如下。

点的计算首先要计算索引值,其计算公式见式(1)。

顶点的计算公式见式(2)。

UV坐标计算公式见式(3)至式(5)。

三角形计算见式(6)。

式中:index为格网索引值;Di mens i ons为生成的海浪的分辨率,分辨率越大代表着海浪细节表现得越充分;uvs为海浪的偏移,即海浪在某时刻的位置;vec为海浪顶点高度;tries为生成的海浪三角网格。

Unity中的网格全是由一个个三角形相互连接构建而成的,所以三角形的生成与存储非常重要,可通过Mesh.vertices函数对其进行保存。

基础网格构建完毕后,保存脚本文件,然后返回Unity中运行,从而生成一个网格模型。由于在编写脚本文件时只声明了海面网格,并没有对网格高度进行计算,所以只能得到一个没有波动的三角海面网格(见图1)。

1.2 高度场生成

1.2.1 Perlin噪声算法。Perlin噪声算法是Ken Perlin提出的一种强大算法,该算法常用于生成随机数,从而被广泛应用于电影、游戏等领域中。在游戏领域中,该算法用于生成各种波形、起伏不平的材质、纹理等,如《我的世界》游戏中的地形就是用该算法生成的。除此之外,该算法还可生成火焰、云等效果。在电影领域中,该算法主要用来生成水面波浪。从本质上讲,Perlin噪声函数是一个随机数生成器,但其与普通的随机数生成器有所不同。Perlin噪声函数是用一个整数作为参数,然后返回一个基于该参数的随机数。为了引入噪声函数的相关概念,用三次函数对其进行插值即可形成连续的噪声函数。

1.2.2 高度场生成。使用二维Perlin噪声建立海浪高度场,通过Perlin噪声建立海浪高度场的步骤如下。

①定义一个晶格结构。构建一个二维平面,同时生成每个顶点的“伪随机”梯度向量,即每个顶点都生成一个伪随机梯度向量。伪随机是指对任意组相同的输入,必定得到相同的输出,且其不是完全随机的,只是在生成函数不变的前提下,每个坐标的梯度向量都是确定不变的。梯度向量是指该顶点相对单元正方形内某点的影响是正向还是负向的。二维Perlin噪声的梯度向量一般用(-1,1)、(0,1)、(1,1)、(-1,0)、(1,0)、(-1,-1)、(0,-1)、(1,-1)这八个向量来表示。采用这些特殊梯度向量是为了避免“镜像现象”。二维情况下的晶格是一个正方形。只要确定左下P0(x0,y0)和右上P1(x1,y1)两个点的坐标,就可确定其所在晶格。

②确定梯度向量,得到点积。由步骤①得到晶格,输入一个点P(x,y),该点即为给定点,可用floor函数求得P0点坐标,见式(7)、式(8)。

式中:x0、y0是P0点横纵坐标;floor函数为向下取整函数,如a=2.2,则floor(2.2)=2.000 000。

根据给定的点P可得到晶格的顶点坐标,即P0(x0,y0)、P(1x1,y1)、P(2x2,y0)、P(3x0,y1)。然后在顶点处生成随机梯度向量,即g00、g01、g10、g1(1见图2)。

图1 海面网格

图2 晶格结构和梯度向量

接着进行点积运算,先要确定晶格顶点到P点的距离向量,用dist i,j来表示,见式(9)。

式中:di st为距离向量;i、j分别取0或1,如i=0,j=0,则P0(x0,y0)到P的距离向量用dist00来表示。则点积计算见式(10)至式(13)。

式中:s、t为点积结果。当两个向量的夹角小于90°时,点积结果为正;当两个向量夹角大于90°时,点积结果为负;当两个向量夹角等于90°时,点积结果为0。

③插值,得到噪声。一般选择缓和曲线作为插值函数,并代入坐标进行线性插值计算。使用缓和曲线计算插值因子时,噪声函数的起点和终点的变化比较缓慢,且中间部分变化明显,也就是说当接近固定点时,变化速率变缓。1985年,Perlin首次提出Perlin噪声时,使用的缓和曲线为y=3x2-2x3。该缓和曲线的一阶导数满足连续性,但其二阶导数在晶格顶点处(x=0或1)不为0,呈现明显的不连续性。所以,Perlin在2002年发表的论文中,将其改进为y=6x5-15x4+10x3,该函数无论是一阶导还是二阶导都满足连续性(见图3)。且函数越是高阶,可导函数的曲线就越平滑,本研究选取y=6x5-15x4+10x3作为插值函数,进行噪声平滑处理。

使用缓和曲线计算插值因子的步骤如下。

首先分别计算出x、y方向的加权因子,见式(14)、式(15)。

然后使用加权因子分别对x、y方向进行线性插值,先对x方向进行线性插值,见式(16)、式(17)。

最后对y方向进行线性插值,得到最终的噪声值,见式(18)。

得到的最终插值图像见图4。

1.3 渲染纹理

使用Shader Graph进行纹理渲染。Shader Graph是在Unity 2018版本后推出的一款通过可视化界面的节点连接来实现着色器的创建及编辑的可编程式渲染管线工具。相较于Unity Shader,Shader Graph的渲染管线不用编写复杂的代码,其图形化编辑界面也更加友好。

Shader Graph有两种打开方式,一是打开Unity编辑器,在创建项目时选择Universal Render Pipeline来创建项目,通过这种方式创建的项目可直接使用Shader Graph,不再进行配置。二是创建一个默认的3D模板,然后安装shader graph和URP渲染管线。其渲染过程如下。

1.3.1 海浪颜色设置。设置两个颜色,分别记为A和B,使用线性插值及菲涅尔效应得到海面颜色(见图5)。

图3 插值函数对比

图4 2D Perlin函数插值图像

图5 颜色光照设置

1.3.2 设置海浪偏移。先设置海浪纹理进行贴图,然后对其UV值进行设置,世界坐标、像素值以及UV值的对应关系为:X-R-U、Y-G-V、Z-B、WA。在Unity中,海平面处于XZ平面,需要R、B对应U、V。接着设置偏移量,通过改变时间,来改变贴图的移动方向。由于一张UV贴图不能体现出海面波浪效果,所以要建立两个方向相反的UV贴图。最后将两条渲染管线贴图效果进行法线融合,将结果连接到Normal中(见图6)。

1.3.3 设置海浪平滑。只要创建一个平滑属性,连接到Smoothness,就可在属性面板进行设置。

图6 偏移设置

2 海浪实现

为了验证Perlin噪声算法生成的海面及添加光照后的效果,进行仿真试验。根据本研究提出的方法,在Windows10 64位操作系统、Unity3D 2020.3.32f1c1平台中,利用C#语言在Visual Studio 2019中编写脚本,天空盒使用系统自带的sky box,最终生成的海浪效果如图7所示。图7(a)为Normal Strength=4、Tilling=0.08时的海面,图7(b)为Normal Strength=4、Tiling=0.2时的海面,图7(c)为Normal Strength=8、Tilling=0.08时 的 海 浪 形 态,图7(d)为Normal Strength=8、Tilling=0.2时的海浪形态。从图7(a)和图7(b)可以看出,在法线强度相同的前提下,Tilling越大,海浪越密集。由图7(a)和图7(c)可知,当偏移指数相同时,Normal Strength越大,海浪的颜色越深,细节表现越明显。当Normal Strength相同时,Tilling指数越大,海浪的波纹越密集,海浪起伏变缓。

Unity3D处理光照和阴影比较方便,通过向场景中添加两个平行光,可真实地表现出白天和夜晚状态下的海面效果,添加光照生成的海面效果如图8所示,图8是在相同Normal Strength和Tilling参数下不同时间的海浪。图8(a)为添加光照,显示为白天效果;图8(b)为关闭光照,显示为夜晚效果。

图7 不同参数下的海浪形态

图8 不同时间的海面

3 结语

本研究利用Unity3D平台,从海面网格的创建出发,利用Perlin噪声生成海面高度场及海面渲染三个模块,对海面建模仿真进行研究,调整光照与法线强度,可方便快速且真实地表现出海面。虽在各个模块都要考虑其仿真效果和真实感,但并没考虑在自然环境下(降雨、风等)的仿真效果,以及没有采用实时数据对海面进行建模,针对上述问题,该方法还有待进一步研究。

猜你喜欢

见式插值海浪
滑动式Lagrange与Chebyshev插值方法对BDS精密星历内插及其精度分析
火花发射光谱法测定钢中锰含量的三种测量不确定度评定方法的比较
丫丫和小海浪
海浪
如何正确运用χ2检验
——人-时间资料率比分析与SAS实现
樊应举
页岩纳米级孔隙甲烷渗透特性模拟
桥(门)式起重机起升机构高速浮动轴设计
基于pade逼近的重心有理混合插值新方法
混合重叠网格插值方法的改进及应用