Unity只在一個面片上實現卡通水效果

概述

因爲項目要做廣大世界那種水效果。想過用類似九宮格之類的來實現。但是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

參考文章及工程:

https://lab.uwa4d.com/lab/5c27e30972745c25a8f1e38d

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章