Shader刚入门没多久,尝试做了一个卡通的海洋效果。做的时候参考了很多大佬的文章,现在写个笔记记录一下。
先看几张图找找感觉:
最能体现二次元海洋的要素就是波形、白沫、折射与次表面散射。
先从波形开始,这里参照了这位大佬的文章:
https://zhuanlan.zhihu.com/p/95482541
下面开始填色,这里先叠了个双层菲涅尔:
代码语言:javascript复制//双层菲涅尔
fixed fresnel = saturate(_FresnelScale (1 - _FresnelScale) * pow(1 - dot(normal, viewDir), 4));
fresnel = fresnel < 0.5 ? 0.05 : 0.4;
half facing = saturate(dot(viewDir, normal));
facing = facing < 0.5 ? 0 : 1;
fixed3 oceanColor = lerp(_OceanColorShallow, _OceanColorDeep, facing);
fixed3 oceanDiffuse = oceanColor * _LightColor0.rgb;
fixed diffuseControl = saturate(dot(lightDir, normal));
oceanDiffuse *= diffuseControl < 0.7 ? 0.7 : 0.8;
根据FFT里传来的白沫RT画上白沫:
不过这样岸边会显得非常唐突,就像是模型莫名其妙就从中间穿过,过于生硬。所以岸边也不要忘记加上白沫。这里需要进行深度采样,并进行分阶。
代码语言:javascript复制//屏幕深度
float sceneZ = max(0,
LinearEyeDepth(
UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos))))
- _ProjectionParams.g);
float partZ = max(0, i.projPos.z - _ProjectionParams.g);
//深度差
float depthGap = sceneZ - partZ;
float shore = smoothstep(0.1, 0.5, saturate(1 - depthGap * _ShoreRange)) > 0.25
? 1
: 0 * _ShoreTransparency;
再涂上颜色:
代码语言:javascript复制//近岸泡沫
fixed foam = shore;
fixed4 foamCol = foam * _FoamColor;
foamCol.a *= _ShoreTransparency;
看起来好了一些。
下面加入反射,这里做的比较简单。
代码语言:javascript复制half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectDir, 0);
half3 sky = DecodeHDR(rgbm, unity_SpecCube0_HDR);
fixed3 halfDir = normalize(lightDir viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb;
fixed specularControl = pow(max(0, dot(normal, halfDir)), _Gloss) < 0.2 ? 0.1 : 0.5;
specular *= specularControl;
specular *= sky * .6;
fixed3 diffuse = lerp(oceanDiffuse, bubblesDiffuse, bubbles);
感觉平静一点的水面才看得比较明显
下面水浅处加一些带有渐变的折射,这里用到了上面算过的深度差
代码语言:javascript复制float linearShore = smoothstep(
0.1, 0.65, saturate((1 - depthGap _LinearShoreRange) / _LinearShoreGradient));
折射也是从GrabPass拿的:
代码语言:javascript复制//折射
fixed4 fra = tex2D(
_ScreenTex,
(i.screenUV.xy _FracIntensity * (saturate(1 - depthGap) 0.5) * sin(2 * _Time.y)) / (i.screenUV.w
));
fra.a = linearShore * _FracTransparency;
现在折射的通透有是有了,但是反而显得岸边特别空。于是我在这里加了个焦散效果:
代码语言:javascript复制//焦散
float3 GetCaustics(float2 uv,fixed factor,fixed offset)
{
fixed2 causticsUv = uv * _Caustics_ST.xy _Caustics_ST.zw;
causticsUv = _CausticsSpeed * _Time.y * factor;
// 分离RGB
fixed s = 1.5 * offset;
fixed r = tex2D(_Caustics, causticsUv fixed2( s, s)).r * _CausticsIntensity;
fixed g = tex2D(_Caustics, causticsUv fixed2( s, -s)).g * _CausticsIntensity;
fixed b = tex2D(_Caustics, causticsUv fixed2(-s, -s)).b * _CausticsIntensity;
return fixed3(r, g, b);
}
/*......*/
fixed3 caustics = min(GetCaustics(i.uv, 1, 1), GetCaustics(i.uv, _CausticsGrow, _CausticsOffset));
caustics *= linearShore;
感觉好多了
最后再加上一点次表面散射,这里参照了这篇文章:
Unity海洋shader笔记①
这下海浪的通透感就出来了:
Shader刚入门没多久,恳请各位批评指正!