一个简单的Unity可控水流实现方式
又更新一下,加了点浪花,gerstner波效果不错,但是我不知道怎么修改波形让他不那么规整,不知道有没有大佬有让gerstner波不那么规整的办法https://www.zhihu.com/video/1454532002493546496
============================================================
gerstner波我试了下,效果气势完全不同了
代码原理奉上,这个大佬讲的很详细:
https://zhuanlan.zhihu.com/p/404778222
====================
1.感谢有大佬给我提供宝贵的意见:有大佬提议将正余弦换成gerstner波代替可能效果会更好,我觉得这个提议实在是太妙了!各位有兴趣的可以去试试,后续有空也要继续改进,其实这个Shader还有很多细节可以做文章。除了浪花波形,还可以加碰撞边缘泡沫,还能增加焦散光,关于流体,一直是特效的热门项目,能做的细节实在太多了。以后升级更新了会继续更新文章的哈。
gerstner波更适合那种粗犷的海浪(但是算法就复杂的多了),正余弦只适用于平静的水面,给大家推荐2篇文章
Justin:Gerstner 水波详解
Unity 水、流体、波纹基础系列(三)--波浪(Waves)
2.有人问我是不是TA,只是个想做TA但是编程和美术都是零基础的小白哈,只是一个小小的菜鸟前端,对于TA这个职业我是一直可望而不可即的哈!毕竟这篇文章唯一有难度的就是这个噪波的实现,而且我也不是代码的生产者,我只是代码的搬运工。也许不难但很关键,只要搞定了噪波,就搞定了近一半的特效了。
3.关于这个海洋插件,雀氏做的不错,但是我说中看不中用,同事自然是很气的。仔细想想:按照2021年的游戏标准,端游Batches要控制在1200以内,手游batches要控制在220以内,这个插件只要一打开就直接飙升至3k+。暂不考虑这个插件在各个平台不会有bug的问题,仅仅是Batches这一项就注定不能做游戏了。可能是拿来做影视用的?但是影视用的这种海面用houdini做不是很简单粗暴么,并且交互的流体只能houdini这种专业特效软件来做,做完直接用houdini的mantra或者Karma或者RS渲染了,当然现在已经有很多影视流程开始用Unreal来渲染了(UE4.27有了离线渲染功能,并且速度直接超过曾经最快的RS了,并且老黄根据皮克斯运用的技术制作的Omniverse这种平台可以各个3D软件实现实时交互,C4D和Blender也有了和UE实时交互的插件了,目测,这种流程的应用只会越来越广泛。虽然我是Unity党,但是不得不承认UE在影视方面雀氏很香),用这个插件的效果自然有点鸡肋了。毕竟市场能留下来的,往往只有走数量最低端和走质量最高端,这种上不上下不下的最难受。所以中看不中用我觉得我说的没错。
===================================================================
分割线===================================================================
最近同事在完成一个虚拟仿真项目中问大伙一些问题,我也去看了下热闹,问题还没解决但是感觉找bug过程中程序很卡。究其原因,这个项目的要求是要有一个可以随时间变化的水面(要求不高,改变水的流向大小等等)。
但是这个项目是一个在浏览器运行的网页端的交互程序,但是Batches 5~6K感觉着实有点为难浏览器了,主要是为了实现这个可以变化的水面在工程中加入了某个插件(不清楚具体是什么,貌似是一个Unity的海洋模拟插件吧),这个插件实现的水面效果挺好的,当然代价就是很吃性能,有点中看不中用。一打开直接飙升3K+的Batches。这个消耗对于端游项目都是直接暴毙的存在。
正好最近看了下Unity Shader方面是一些资料,比较感兴趣,就写一个简单的可调节水流的水面shader练练手。
我就在这简单分享一下自己的做法,传道不传术,基础Shader 矩阵转换那些我就不细说了,网上资料也很多,我也就不废话了,有大佬有更好的实现思路欢迎在评论区补充。shader代码写起来很简单,重要的是思路。
正文开始:怎么样实现一个流水的效果呢?
1.法线+置换(normal & displament)
如果要求不高,很多游戏或者程序里面采用的做法都是给一张水面波纹的贴图来影响平面的法线,然后偏移法线的uv即可实现一个简单水面的定向移动。这种做法很经典很实用并且效果也是不错的。上面提到的水流方向的效果其实也就已经实现了,但是这个项目的要求是水面的幅度也是会变化的,毕竟法线改变的只是表面光线的反射角度,并没有让模型表面发生形变,用法线强度来调节模型的表面凹凸,能调节的幅度十分有限并且效果比较一般,在角度和光线不是很好的时候几乎没有效果。
所以,要实现水面可以调节大小的功能,用只改变法线(normal)的方式显然是不够的,我要的是能真正改变模型顶点的置换(displament)效果。
这时候美术可能就比较头疼了,在unity的可视化Shader编辑器中是没有置换节点的(隔壁虚幻的材质蓝图可是有的,不知道unity为啥不封装一个)。不过问题不大,因为本身用的就是unity最基础的Build-in管线,支持的可视化Shader插件也不多,代码实现置换效果也是十分简单的。
2.三角函数(sin & cos)
怎么最简单画一个流动的水面呢?幼儿园小朋友都知道——画几条波浪线就完事了
说到波浪线,自然就都知道我要用什么函数了吧。(其实不说也知道了,小标题出卖了我)。好了,这一点说完了,只需要让顶点的起伏按照波浪线排列就ok了。要让他动起来也简单,偏移正(余)弦函数的相位就ok了,要调节的他的高度只需要改变正(余)弦函数的振幅就可以了,要改变浪花的密集程度也只需要改变函数的频率就ok了。
好了,没错,你学废了,分享完毕!
如果要求不高,比如我这个项目做到这,其实已经都实现了项目的基本要求了,后面也就不用管了(好像本来这项目就不用我管哈)。
但是,很多人应该都会想到一个问题吧,这样导致的问题就是水面波浪都是十分工整规律的排列,压根就不像是水。所以后面的内容估计才是很多人想知道我怎么解决的。
3.再加亿点点细节——万物皆可噪波(noise)
没错,自然规律是熵增的,是趋于混乱无序的,而规律的反义词就是随机,很多小机灵鬼估计就开始用随机数了吧,你可以试试,效果应该会好点,但是多少会有点奇怪。仅用随机生成的数,出来的随机会特别的离散没有规律,也就是这种类似电视机花屏的白噪声
貌似还能用,但是肯定不够完美,你可以像其他大佬一样加个渐变(gradients)
比如这位大佬,效果已经好很多了,可以直接使用下试试,不过我使用的不是这个。
https://blog.csdn.net/qq_23030843/article/details/104353774
很多美术估计早就想到了,估计都没耐心看了,不就是个噪波嘛,废话这么多。
没错,你玩各种设计软件,3D软件,渲染器或者可视化Shader编辑器,都能给你生成各种noise,确实都有各种现成的封装好的节点,但是unity的Shaderlab并没有给你封装,
那怎么办呢?不用呗,或者自己写一个?
经常从事图形相关的设计师或者美术尤其是玩渲染或者特效的,肯定经常会接触到各种噪波贴图,这些噪波贴图你会发现很随机但是又不会过于离散,这类贴图的颜色过渡十分的平滑,不至于太跳,这就很奈斯了,正是我们想要的。最常见的就是柏林(perlin)噪波,simplex噪波,湍流(turbulence)这些了。
你可能直接就生成或者下载一个直接来用了,但是毕竟是一张贴图,精度会有限制。
你想了解这种程序化怎么来的,去知乎百度都能搜出来一堆,估计你又会来气了,说了一堆叫我去百度?
百度过后你会发现,虽然很多,但是看起来估计很懵逼,我也是,这个以后有兴趣可以慢慢研究,我只要有一个noise就行了,至于是选择哪种noise都差别不大,看哪个顺眼就用哪个,但是用习惯就建议只用一种,他们调节起来的大小参数也都会是你所熟悉的。
话不多说:直接上代码:
https://blog.csdn.net/qq_36107199/article/details/87191348
这个链接里几种常见的noise代码都写好了,只需要开启程序员的终极奥义——CV大法(粘贴复制)即可
我的做法就很简单,就是用噪波配合三角函数作用于我的vertex的世界坐标y坐标,让vertex的y坐标根据自身的x和z的值有关联即可,这样就有一个保持了一定正余弦函数规律带有很多细微变化细节的波浪了。
我使用的代码如下:
o.Sin_srcPos =half4(world_srcPos.x+_noise2*0.001,_hight_z*sin(_frequency_z*world_srcPos.x + _speed_x*_Time.y )+_noise3*_hight_x*cos(_frequency_x*world_srcPos.z + _speed_z*_Time.z)+_noise,world_srcPos.z-_noise*0.001,world_srcPos.w);
得到三个noise 在让xz只分别受到这个noise一点点影响,这样顶点在水平方向也就可以有一个轻微的扰动,另外垂直方向的高度基于x和y的世界坐标位置的同时也让其幅度会和x和z的noise值的有一定关联,给一个合适的系数让他有肉眼可见的影响即可,并且这种起伏变化不会太跳戏,是过渡十分缓和圆润的,以保证波浪的形状大致是一个有高低起伏平滑变化的三角函数即可。
这里要注意的是,这个三角函数必须是用于顶点上,并且一定要要在顶点的模型左边转化成世界坐标之前进行该操作。这样你就会发现得到了一个比较不错的网格。并且在此处设定一些调整高度的属性,这样就可以根据需要对水面的高度对材质进行脚本控制来调节水面高度,在频率和偏移速度处同理,这样就可以调成整个网格的具体形态和变化速度。
这也就实现了我想要的置换效果了,当然,要想置换效果好,模型顶点就得足够多,模型面数必须得足够高才行,我用的是一个分段100*100的平面。
噪波的使用太常见,作用又很直接,噪波不管用于粒子烟火流体的发射源上还是渲染的通道上都能提供更加丰富的变化,增加大量的细节来提升真实感。
4.再加亿点点细节——叠加法线(normal)
然而模型的面数是有限的,想通过顶点动画来提供足够多的细节对于性能的消耗也是十分巨大的。顶点动画实现了,水面的立体变化也就实现了,所以剩下的就是通过法线贴图来增加亿点点细节。
一张贴图能提供的细节是十分有限的,由于是通过偏移UV来实现水面流动的视觉效果,仅用一张贴图就会发现模型表面的起伏没多久就又重复了,这样的规律变化就会让人感觉很粗糙很假。
这里你为了变化更多样,完全可以继续使用之前的noise来实现,我采用的是用一个水波纹的法线贴图进行采样,
然后用到了一个常用的比较讨巧的做法,就同样的纹理复制一份然后将二者的纹理进行混合,两张纹理在大小和速度方向上只要有一定的差别,那么纹理重复循环的周期就会变得很长,从而给人一种没有重复,无限细节的错觉。
具体实现的关键代码也很简单(至于怎么从模型空间到切线空间的转化我就不不细说了,相关资料也很多),和前面一样,系数不重要,有差别即可,当然具体效果还是需要自己调整一个合适的范围。
5.再加亿点点细节——万物皆可菲涅尔(fresnel)
其实到了这一步也就基本做出来,大家都知道水面是啥样的,同样的水面,时而清澈透明可一眼窥底,时而如翡翠碧玉一般带有颜色,所以呀,要想水有足够的真实感,尤其是动态的水,那么他的颜色和透明度必然是有变化的,这个变化和人与光线的视角都有关系,一般近处正对着水面时候水是很清澈的是透明的,远处的水都是带有颜色的,根据这样一个现象,只需要有一个依据光线和视线角度的混合即可增加不少细节,给人一种很真实的错觉。
菲涅尔也是一个常用的衰减贴图,在渲染时候加上一点点菲涅尔的颜色混合可以让模型表面颜色有一个渐变效果,使得物体表面颜色变化更加丰富,并且会增添很多的透视感以及立体感。
6.一些细节补充
由于水是透明的,所以其漫反射(也就是自身颜色)比重并不大,透明物体的颜色也主要由可以穿过的光线决定,水这种透明物是没有颜色的,我们看到的颜色主要取决于水反射和透过水的颜色。
首先是透明物体,不用说了RenderQueue值就要设置为3000了,然后Zwrite写入可以关了,这里由于项目需要钻进水底查看,所以我把默认背面裁剪也给关了,不同的Blend 混合方式也会带来完全不同的感觉,比如OneOne叠加颜色就会比较亮,水就会变得很清澈,但是问题也就是很容易过爆出现死白,用在一些二次元的水面效果也许还行,大家不明白各种叠加的含义完全可以通过调试来理解,如果你对这方面感兴趣,说明你的视觉比其他方面更敏感,那么就让眼睛来给你一个反馈会映象更加深刻,理解更加透彻。
这几行代码别忘了调整哦:
最后的菲涅尔叠加效果也很简单:
当然:这里你也可以通过一个值来改变pow函数的输入参数,用来控制菲涅尔的强度
此处的texColor是我定义的一个属性,再次进行叠加会让水面增加更多的颜色细节,这种图片会随着vertex一起飘动,使用一些天空来模拟倒影或者一些水底照片来模拟水底都能为水面效果增色不少。
非常感谢您能看完我的分享。
话不多说,附上我B站视频的链接,可以看看水面的最终效果,觉得对您有帮助记得点赞关注和三连哦(当然如果附加的链接对您有帮助也别忘了给源链接的博主一个点赞哦)
https://www.bilibili.com/video/BV1y44y1a75p?spm_id_from=333.999.0.0
当然,要想实现一个真实的流体效果,不可能是一个Shader能实现的,一套流体系统其实是非常复杂的,如果想制作真实的影视级别流体效果,建议还是交给Houdini,Realflow这样的专业特效软件来制作吧,这只是一个节省性能的讨巧做法。
毕竟,都流畅实时了还要啥自行车。至于流体也一直是我所感兴趣的,后续如果遇到了不错的插件或者比较好的实现方法还会继续更新 怎么会很气呢 只是觉得你效果没有别人的好 差的很多 你一直一味的强调性能好比在跟客户说一样 客户要的效果 那你又做不到跟他的插件实现一样的效果 并且新能比他的更好 才有资格说出中看不中用吧[好奇] 你都说了是仿真了 关键它不真啊 别急,会慢慢完善的
页:
[1]