unity透明通道加颜色_Unity只在一个面片上实现真实水体渲染

b31b466010bd623d5871a114b9133ebe.png

2cf1297d4bbdb143adb13389837c681c.gif

上面是效果图,题目指的一个面片是指只有两个三角面组成的面片,只有四个顶点。

勘误:

我发现水面的高光效果在安卓手机上失去了效果,具体原因如下:

halfDirection 得用下面的Unity_SafeNormalize方法,而不是normalize,

否则在手机上高光会失去效果,修改如下:

float3 Unity_SafeNormalize(float3 inVec)
{
       float dp3 = max(0.001f, dot(inVec, inVec));
       return inVec * rsqrt(dp3);
}

然后

float3 halfDirection = Unity_SafeNormalize(viewDirection+ lightDirection);

概述

因为前一版卡通水体制作人觉得效果一般,所以换成了《海岛纪元》这种风格的水体。

这次我使用截帧工具,这次使用RenderDoc来截帧,效果还不错。

d0226e621e21fc8d62af8d9d5ac335fc.png

本来打算复刻一版的,后来发现他们貌似不是用unity做的。代码风格有点不一样。

其实是因为我看不懂他们的代码。。下面我会分析实现的理论和讲述具体实现。最后给出demo下载。

具体实现

通过截帧工具可以看到:

生成浪花的贴图是由lightmap和一个Rays贴图来渲染的。

04efc8daaa5e0314fe95ec8391303a0a.png

而且浪花是单独一个mesh,这波操作其实我是看不懂的。原本以为通过shader在一个面片上就可以实现类似效果。

ec4560ed59bf976916c05c21a41b7f46.png

​他们浪花的渲染效果大概如下:

3e039b13582c28de8cb553845bf287d7.png

​再看一下他们水的效果:

7984a1fc298cd425a98d9a765e204c30.png

​1、使用了深度值来区分水深颜色

2、使用了法线贴图数据扰动来做水波纹效果

3、冲向岸边的浪花基本是实心的白色线条

4、反射和折射,反射用了环境贴图(并非是cubemap)

5、有高光,为什么他们的高光这么柔和。

它们所使用的贴图如下:

4930c55c617ba0b31291181861fc3440.png

大概知道原理,就可以做了。

首先采样法线贴图扰动来做波纹效果:

//采样法线贴图的uv坐标,和时间相加 
o.bumpUv1.xy = v.uv + float2(_SinTime.x * _WaveSpeed.x, _SinTime.x * _WaveSpeed.y); 
o.bumpUv1.zw = v.uv + float2(_CosTime.y * 1.2 * _WaveSpeed.z, _SinTime.y*0.5* _WaveSpeed.w);

//法线贴图  
half4 bump10 = (tex2D(_DumpTex, v.bumpUv1.xy / _NormalsScale) * 2) + (tex2D(_DumpTex, v.bumpUv1.zw / _NormalsScale) * 2) - 2;  
half3 oriOffset = UnpackNormal(bump10);  
oriOffset.xy = oriOffset.xy * _NormalsStrength; 
 bump = normalize(oriOffset);  
half2 offset = oriOffset.xy; 
//采样折射贴图(地面) float4 refraCol = tex2D(_MainTexture, v.uv.xy + offset );

注意上面使用了不同的uv坐标采样两次法线贴图的数据,并各自乘以2后相加的结果减去2。

这样的目的是为了使得波纹有交叉扰动的感觉。

接着采样深度贴图,做出水浅,水深过渡的效果。

//深度贴图 float zdepth = tex2D(_DepthTexture, v.oriuv).r; 
//把深度强的地方增强,弱的地方变化不大,这步可做可不做,具体看效果  zdepth = pow(zdepth, 1.3); 
float depthDifference = zdepth * _FoamDeP; float waterDepthDifference01 = saturate(depthDifference);  
waterDepthDifference01 = pow(waterDepthDifference01, 0.8);  
//根据深度值插值颜色 
float4 lightColor = lerp(float4(1, 1, 1, 1),_DepthGradientShallow , smoothstep(0,0.5, waterDepthDifference01)); 
float4 waterColor = lerp(lightColor, _DepthGradientDeep, waterDepthDifference01); float alpha = smoothstep(0, 0.1, zdepth);

再接着做实线的浪花

//浪花贴图  float4 FoamCol = tex2D(_FoamTexture, v.foamuv); 
//根据深度值来显示透明度  float FoamAlpha = (FoamCol.r + (FoamCol.g * cSecondWeight)); 
FoamCol.a = FoamAlpha;  
half waveFaInner = _waveFaMax - _Time.y * _WaveSpeed.x * _waveFaSpeed % (_waveFaMax);  
waveFaInner = clamp(waveFaInner, _waveFaMin, _waveFaMax); 
//是否显示浪花  half borderFlag = step(zdepth.r, waveFaInner) * step(waveFaInner - _line, zdepth.r);   
half4 border1 = FoamCol.a * borderFlag * _specularColor * (alpha);

然后就可以得出水体的颜色了:

float4 finalCol = float4(refraCol.rgb * waterColor.rgb, alpha);
 half4 cc =  finalCol+ border1;

最后加上高光,

刚开始高光是想用blin-phong做的,效果不太好,感觉是一片片的生硬的色块,不仅有锯齿,还没过渡的感觉。

而海岛纪元的高光真的过渡很柔和,很真实。难道是PBR的高光渲染?

试了一下,果然是真的。

所以这里我用到了PBR的高光,也就是BRDF高光公式

//高光,PBR的高光 
 float roughness = 1.0 - _Smoothness; 
roughness = max(roughness, 0.002); 
float roughness2 = roughness * roughness; 
//d项 
 half dCol = BRDF_DTerm(NdotH, roughness2);  
G项
 half gTerm = BRDF_GTerm(NdotL, NdotV, roughness2);  
F项 菲涅尔  
half3 frenCol = BRDF_FresnelTerm(_specularColor.rgb, LdotH); 
float specularPBL = dCol * gTerm * UNITY_PI * frenCol; 
 //不会为负数 
specularPBL = max(0, specularPBL * NdotL);  
//any 参数里的任意一个元素不为零   
specularPBL *= any(_specularColor.rgb) ? 1.0 : 0.0; 
//加上高光,得到最终的颜色  
float4 outCol = cc + float4(specularPBL * mainLight.color, 1) * alpha;  
outCol.r = clamp(outCol.r, 0, 1);  
outCol.g = clamp(outCol.g, 0, 1);  
outCol.b = clamp(outCol.b, 0, 1);  
return outCol;

高光的感觉自然多了!

6787c3587b46e9aa4811e47b4f937d51.png

demo下载,记得在URP环境下使用:

链接:https://pan.baidu.com/s/11D5koAJSypTpaw_7G-F7Fg
提取码:tuf1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值