在移动设备端实现美丽的海面效果(波光+渐变+实时倒影)

在移动设备端实现美丽的海面效果(波光+渐变+实时倒影)

我们的项目为了还原漫画中海滩度假胜地的场景,想要做出一个美丽的海岛风景,那么随之而来的一个大问题就是如何把海面做的漂亮,如何在限制诸多的移动平台上把海的效果做好。网上可以找到很多做海面效果的文章,很多游戏里也都实现了水面的效果,然而很多情况是,手机上的水面效果都不尽如人意,有些比较像水银,有些层次感不够明显。本文将介绍一下我们项目中是如何努力在移动平台上实现一个较为逼真柔美的海面效果的。

首先上两张整体效果的截图。可以看出海水会根据地势的深浅渐变颜色,水面也有粼粼波光与近树远山的倒影。接下来的部分,将会针对各个效果分别介绍。

请输入图片描述
纵览效果

请输入图片描述
游戏视角

先从生成水面的第一个步骤开始入手。

一、生成水面的面片

请输入图片描述
图片为实验工程,不代表游戏中的效果

请输入图片描述
上图工程生成的水片

一张完整的Mesh是如何决定哪里有水,哪里是高地需要透明,又如何根据不同高度表现出颜色变化的呢? 我们利用了顶点色存储高度信息。

项目初期,以及网上很多例子的实现方法,是计算深度(Depth Map)。虽然实现出来的效果很美好,但可惜的是,由于移动端上精度不足,无法正确计算相机到物体的准确Depth值,导致计算的海水效果错误。所以精细的海面效果无法用这个方法在手机上出现。因此。需要找到一个不借助Depth Map来计算的方法。最后,我们利用了刚刚提到的顶点色。

在Mesh中,顶点信息有顶点色和RGBA,如果Mesh的顶点色并没有其他用处,则完全可以利用起来,存储一些其他的信息比如说存高度信息等。其实也可以把预处理的高度信息存在贴图中,但存在一个已有的且没有被合理利用的通道中,更简单高效。

在前期准备的阶段,计算水面与地的高度,并存在Mesh中的工具是MeshSaverEditor.cs。在运行时,右键点击Tile的Mesh组件,有一个“Save Mesh As Color...”选项,可存下一个带有高度信息的Mesh。再将生成的Mesh赋给自己,就可以利用这上的信息了。

工具的核心原理是利用射线测量水面到地表的距离,再将距离数据转化到Mesh顶点的颜色通道中。

上述步骤在确定调整好水片位置后,无需再次生成,也不会占用真机运行时的效率,所以非常高效。

二、产生波光

请输入图片描述
水面的波光效果

能有波光粼粼的感觉,主要是有一个Normal Texture。

实现的主要代码:

half3 normalInTan = UnpackScaleNormalDIY(tex2D(_BumpMap, i.bumpCoords.xy)+ tex2D(_BumpMap, i.bumpCoords.zw), 1.0f);   //纹理坐标的前两个值+ 纹理坐标的后两个值

三、水面的层次感

请输入图片描述
为了更好的看到水本身的层次感,去掉了倒影

核心代码:

===>       baseColor = baseColor - edgeBlendFactors.x*0.3 + (spec * 
_SpecularColor)/(edgeBlendFactors.x+1) ;
===>       baseColor.a = _Transparency * edgeBlendFactors.x* saturate(0.5 + refl2Refr * 1.0)*2;

这里面有一些参数,纯属我个人的经验值,在调整颜色变化的时候,尝试出来的。

这个效果的实现,是以第一步存下来的深度信息为基础的。主要是通过edgeBlendFactors.x来控制,深浅变化的一个量。我在特别靠近岸边的地方加了一圈白,其实是模拟了真实海岸的感觉。

请输入图片描述
参数截图

单纯调整edgeBlendFactors.x 会造成整体上的改变,深浅的渐变区域被拉的很长,不够真实;岸边过于透明,会穿帮露出下面的鱼。所以每一次调整都需要很多相应的配套改变才能出现合理的效果。

游戏中把海面做的特别好的例子,可以参考非常有名的《神秘海域4》,下面这张是游戏里的截图,可以看到很多海面效果的特点,比如浅海深海的不同颜色,海岸线的处理,波涛的起伏。显然,我们的效果距离这个还有很大的差距,不过希望大家之后可以在手机上作出超过《神海》的美丽大海。

请输入图片描述
《神秘海域4》游戏视频截图

其实在CS存高度信息的阶段,我做了下分段,在不同的高度范围之间的颜色是不连续的,这一处理是想模仿《神4》里浅滩是浅蓝带白,深海是深蓝这个特点,中间有一个明显的分界线。

四、实时倒影

请输入图片描述
游戏截图

首先通过PlanarReflectioon.cs控制拍摄需要映照的物体以及参数。Reflection Mask中可以选择Layers,选中了的Layer就可以映在水面上。要注意,不能选择映照本身Layer。ClipPlaneOffset 可以调整倒影的偏移。生成的Texture会赋给Shader的InternalReflection这个变量。

在处理倒影的时候,也出现了一些小问题。有些倒影到了屏幕边缘会被拉伸变形严重,所以调整了一下系数,从10改到1倍,这个问题就可以规避掉了。

代码如下:

half4 distortOffset = half4(worldNormal.xz * REALTIME_DISTORTION * 1.0, 0.0, 0.0); 

另外一个问题是当拉伸没那么明显后,就发现倒影会一直延伸到陆地上。解决的方法依旧靠顶点色传过来的这个高度参数,越浅的地方,反射越小。

代码如下:

refl2Refr = refl2Refr * edgeBlendFactors.x; 

到这里,这一关卡的海面效果实现就全部介绍完了,最后的完成效果就如同最开始的两张图片,有兴趣的可以去游戏中试玩一下。这里也有一个我用手机录制的视频:

就如同上面对比《神海》,我们的海面效果距离完美还很远,有很多地方可以提高,效率上也一定有很多地方可以优化,最后附上核心代码的下载,希望大家可以一起讨论。欢迎指出实现上的不足,和可以提高的地方。

度盘链接: https://pan.baidu.com/s/1nwUCwHF 密码: bapb

在制做这个场景期间,看了很多大海的照片,甚至晚上去后海,都会注意着灯光下的水面波纹,才发现,原来以前有很多很美的细节都没怎么注意过。果然做场景效果,还是要多观察生活才能做的出来。


这是侑虎科技第356原创文章,感谢作者Luisa Z供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)

作者知乎:https://zhuanlan.zhihu.com/taiyouxi,同时,作者也是U Sparkle活动参与者哦,UWA欢迎更多开发朋友加入U Sparkle开发者计划,这个舞台有你更精彩!

  • 陈静 发表在 2018年03月27日 回复

    请问完整的工程的云盘资源能不能再发一次呀?前面的密码不正确了,谢谢!

  • zero 发表在 2018年02月23日 回复

    你好,GameSettings这个找不到呢,麻烦看一下,谢谢

  • 邹春毅 发表在 2018年02月05日 回复

    你好,FX/SimpleWater4中WaterInclude.cginc找不到

    • 邹春毅 发表在 2018年02月05日 回复

      感谢作者重新补上了文件https://pan.baidu.com/s/1nwUCwHF,密码:bapb

      • 陈静 发表在 2018年03月27日 回复

        请问有没有完整工程呀?文章上面的那个的密码不正确了