概述
因为项目要做广大世界那种水效果。想过用类似九宫格之类的来实现。但是CPU压力比较大。
也试过用通过世界坐标采样河流数据贴图的方式,来不断刷新跟随摄像机的一个面片。
理论上是可以的,但实际上,会有抖动的效果,初步分析的原因是世界坐标移动的位置要刚好等于偏移整数个采样的像素的距离才
不会抖动。但是具体怎么改真是头疼。
所以想采用一个最简单,也是有点蠢的方式,就是只使用一个面片。笼罩在整个世界地图上,并通过采样河流数据贴图
的数据把整个水体渲染出来。这样一来只用到GPU渲染,CPU压力几乎忽略不计。
二来不会有任何抖动的感觉。
具体实现
我是参考了uwa4d上的一篇卡通水渲染来做的。但是该作者的做法是使用depth值来判断水深和水浅的位置。
我只有一个面片,地面也是一个面片,所以无法通过深度值来判断,需要修改一下,使用采样河流等数据贴图来实现类似的效果。
其实也是上一个TA的做法,哈哈哈,前人栽树好乘凉。
先处理河流的数据贴图,步骤如下
1、把水单独放到一个图层。
2、新建一个图层,做全黑色的背景
3、再新建一个图层,选区水的图层后,在该图层-> 选择->收缩1像素
4、再-> 选择->羽化1像素
5、用油漆桶往选区里倒入纯白色
6、导出为jpg格式即可。
结果大概是下面这样,只有黑白灰,同时白色和黑色之间有过渡。
接着我们采样该贴图,使用贴图颜色来替代深度值(实际上rgb三个通道都可以,这里使用的是g通道):
//采样数据贴图
half4 diffColor = tex2D(_SurfaceShow, i.uv);
//把强的点变弱,弱的变化不大
diffColor=pow(diffColor,0.7);
//根据采样的颜色值替代depth
float existingDepthLinear = diffColor.g * _FoamDeP;
float depthDifference = existingDepthLinear;
//将深度值修正为0-1的范围
float waterDepthDifference01 = saturate(depthDifference / _DepthMaxDistance);
//根据深度值插值颜色
float4 waterColor = lerp(_DepthGradientShallow, _DepthGradientDeep, waterDepthDifference01);
//做一个透明度的过渡,避免边缘太锋利。
waterColor.a = smoothstep( 0,0.1,diffColor.r);
再接着使用viewNormal的法线值插值获得浪花最大最小值。
float3 normalVal = saturate(i.viewNormal);
//根据法线值插值
float foamDistance = lerp(_FoamMaxDistance, _FoamMinDistance, normalVal);
float foamDepthDifference01 = saturate(depthDifference*0.05/ foamDistance);
float surfaceNoiseCutoff = foamDepthDifference01 * _SurfaceNoiseCutoff;
紧接着采样水面歪曲贴图,该贴图主要使用RG通道的值。
然后使用歪曲贴图的数据和Time来修改uv,采样噪声贴图的r通道值。
//采样表面歪曲贴图
//歪曲噪声UV基于RG通道,这里使用xy。
// Distort the noise UV based off the RG channels (using xy here) of the distortion texture.
float2 distortSample = (tex2D(_SurfaceDistortion, i.distortUV).xy * 2 - 1) * _SurfaceDistortionAmount;
//使用time来做偏移
float2 noiseUV = float2((i.noiseUV.x + _Time.y * _SurfaceNoiseScroll.x) + distortSample.x,
(i.noiseUV.y + _Time.y * _SurfaceNoiseScroll.y) + distortSample.y);
//采样表面噪声贴图r值
float surfaceNoiseSample = tex2D(_SurfaceNoise, noiseUV).r;
//使用smoothstep确保我们是抗锯齿的波浪
// Use smoothstep to ensure we get some anti-aliasing in the transition from foam to surface.
// Uncomment the line below to see how it looks without AA.
float surfaceNoise = smoothstep(surfaceNoiseCutoff - SMOOTHSTEP_AA, surfaceNoiseCutoff + SMOOTHSTEP_AA, surfaceNoiseSample);
使用噪声贴图的r值来平滑并调整surfaceNoiseColor的alpha值。clip掉数据贴图颜色值接近0的像素点。
最后混合浪花和水的颜色。
float4 surfaceNoiseColor = _FoamColor;
//使用surfaceNoise使得alpha值发生改变
surfaceNoiseColor.a *= surfaceNoise;
//表面噪声贴图的r值
half noisesurface=surfaceNoiseSample.x*0.03;
half _Cutoff=0.06;
//把没有海浪的地方都裁剪掉
//diffColor.g - _Cutoff+noisesurface小于0就丢弃
clip(diffColor.g - _Cutoff + noisesurface);
//混合波浪和水的颜色
half4 cc = alphaBlend(surfaceNoiseColor, waterColor);
return cc;
最终效果如下:
demo下载:
链接:https://pan.baidu.com/s/1oIj5O5xNz-mdi7Kkja8ElA
提取码:mbc8
参考文章及工程: