这个效果借鉴自unity例子angrybot,并做了一部分适应项目的修改。
angrybot的实现方法
单个雨滴 RainBox
1.Start的时候从Mgr里面取一个雨滴的mesh给MeshFilter使用。
2.在Update 做下落的循环位移。
3.OnBecameInvisible / OnBecameVisible 可见和不可见的时候设置gameobject的enabled属性,性能优化。
雨滴管理器 RainManager
使用generateNewAssetsOnStart来控制是否在start里面创建雨滴的mesh,正常启动游戏的时候需要把这个开关关掉。这个mgr其实就是个存储雨滴mesh的容器,提前把start里面生成的mesh预设给preGennedMeshes,然后rainbox按顺序从这里面循环着取来用。
生成mesh的算法比较好懂,值得注意的是这一句,
uvs2[i4 + 0] = new Vector2(Random.Range(-2,2)*4.0, Random.Range(-1,1)*1.0);
uvs2[i4 + 1] = new Vector2(uvs2[i4 + 0].x, uvs2[i4 + 0].y);
uvs2[i4 + 2] = new Vector2(uvs2[i4 + 0].x, uvs2[i4 + 0].y);
uvs2[i4 + 3] = new Vector2(uvs2[i4 + 0].x, uvs2[i4 + 0].y);
给了第二套UV,并且值是个随机数,这个是给shader用的,后面会说。
shader Rain
VS:v.vertex.yzx += v.texcoord1.xyy;
这里面就用了之前给的uv2了,通过一个随机数,给每个雨滴一个随机的偏移,实现雨滴下落的层次效果,不然雨滴会像个盒子一样一起下落,一下就高大上了很多。
其余没什么特别的
地面水花效果
水花 RainsplashBox
和RainBox基本一样
管理器 RainsplashManager
原理和RainManager一样,uv2一样是个随机数,给shader用的
shader RainSplash
VS:
在VS里面做了个uv动画,实现水花从小到大的效果
half timeVal = frac(_Time.z * 0.5 + v.texcoord1.x) * 2.0;
o.uv.xy = v.texcoord.xy;
v.texcoord1.x 是之前给的随机数,这样各个水花的第一帧就不一样了,实现雨滴交错落地的效果。
<span style="white-space:pre"> </span>o.uv.x = o.uv.x / 6 + floor(timeVal * 6) / 6;
实现序列帧效果,frac取一个数的小数部分,所以timeVal在[0,2)。当timeVal在(1,2)这个区间时,如果texture的warpmode是clamp,就会采样不到颜色,这样贴图取到最后一帧后就会出现一个间隔,水花效果就比较自然。如果是repeat的,就会出现一个水花连续展开的现象。注意,例子给的水花贴图是NPOT的,在andorid下是不能设置为repeat的。
<span style="white-space:pre"> </span>o.color = saturate(1.0 - timeVal) * _Intensity;
当 timeVal 在(1,2)这个区间时,o.color就是0。结合PS中的,
<span style="white-space:pre"> </span>fixed4 outColor = tex2D(_MainTex, i.uv) * i.color;
这样 timeVal > 1的时候水花就消失了,其实也是实现了水花间隔展开的效果。
我的实现
我把生成mesh的代码单提了出来,分别放在 KRainSplashBuilder和KRainModelBuilder里面,然后在Editor里面做菜单项,这样就可以按需要生成mesh了。
雨效果控制器 KRainEffectManager
这个是个开关,当游戏使用低配的时候需要关闭雨效果以减少开销。
使用
1 在场景中种一个emptyObject(取名rainroot),挂载KRainEffectManager。
2 在rainroot下面加两个emptyObject(分别取名RainEffect和RainSplash)
3 制作雨滴prefab,挂载RainBox脚本,给MeshFilter挂上需要的mesh,然后挂在各自的父节点上,调整好位置。
4 制作水花prefab,参考雨滴。