前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Unity Shader】卡通海洋

【Unity Shader】卡通海洋

作者头像
HkingAuditore
发布2023-10-26 17:37:42
2540
发布2023-10-26 17:37:42
举报
文章被收录于专栏:HkingAuditoreHkingAuditore

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刚入门没多久,恳请各位批评指正!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档