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

【Unity Shader】绒毛草坪

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

这是一个一年前就想实现的效果,不过当时技术力太差,一直没能实现理想的效果。

初学Shader,这篇文章可能有不少错误,还请各位大佬批评指正。

后来参考了这篇文章的思路,相信很多人都看过,核心思想就是通过多个PASS的堆叠实现出类似毛发的效果:

先打个简单的底色,这里最好要加上AO贴图。

AO贴图

代码语言:javascript
复制
                v2f vert(appdata_base v)
                {
                    v2f o;
                    o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.worldNormal = UnityObjectToWorldNormal(v.normal);
                    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                    TRANSFER_SHADOW(o);
                    return o;
                }

                fixed4 frag(v2f i): SV_Target
                {
                    
                    fixed3 worldNormal = normalize(i.worldNormal);
                    fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                    fixed3 worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                    fixed3 worldHalf = normalize(worldView + worldLight);
                    fixed shadow = SHADOW_ATTENUATION(i); 

                    fixed3 col = tex2D(_MainTex, i.uv.xy).rgb * _Color;
                
                    fixed ambient = lerp(0,1,(tex2D(_AOTex,i.uv.xy*5).r + tex2D(_AOTex,i.uv.xy*5).g + tex2D(_AOTex,i.uv.xy*5).b)*.657);
                    fixed4 ambientCol =fixed4((ambient * _AOColor).rgb,ambient*0.5);

                    fixed diffuse =lerp(0,1,saturate(dot(worldNormal, worldLight))*shadow);
                    fixed4 diffuseCol =fixed4((diffuse * _LightColor0).rgb + ((1-diffuse) * _ShadowColor * 0.5).rgb,diffuse);

                    fixed specular = pow(saturate(dot(worldNormal, worldHalf)), _Shininess*2.5)*0.85;

                    col = col*(1 - ambientCol.a) + ambientCol * ambientCol.a;
                    col = col * diffuseCol * lerp(0.86,1.4,specular-ambient*0.2)  ;

                    fixed3 color = col + diffuse;


                    return fixed4(col ,1);
                }

可以得到这样的效果:

现在开始最核心的部分,利用多pass进行类似毛发的效果。由于每一个PASS进行的操作过于雷同,不妨把每个pass的内容写进一个单独.cginc文件中,在shader里include一下就好了。Shader只需要传入一个FURSTEP控制每个PASS相对于上一个PASS的移动量即可。

代码语言:javascript
复制
            Pass
            {
                CGPROGRAM
                
                #pragma vertex vert
                #pragma fragment frag
                
                //...其他一些include

                #define FURSTEP 0.03
                #include "FurPass.cginc"
              
                ENDCG
                
            }

在vert中对每一个pass沿着法线方向做偏移操作,顺便加上一个风动效果:

代码语言:javascript
复制
v2f vert(appdata_base v)
{
    v2f o;

    v.vertex.x += ( sin(_WindDistribution + _Time.y * _WindFrequency) * _WindAmplitude) * v.texcoord.y*FURSTEP;
    v.vertex.y += ( cos( _WindDistribution + _Time.y * _WindFrequency) * _WindAmplitude) * v.texcoord.y*FURSTEP;

    float3 P = v.vertex.xyz + v.normal * _FurLength * FURSTEP;
    P += clamp(mul(unity_WorldToObject, _ForceGlobal).xyz + _ForceLocal.xyz, -1, 1) * pow(FURSTEP, 3) * _FurLength;
    o.pos = UnityObjectToClipPos(float4(P, 1.0));
    o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    o.uv.zw = TRANSFORM_TEX(v.texcoord, _FurTex);
    o.worldNormal = UnityObjectToWorldNormal(v.normal);
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    TRANSFER_SHADOW(o)  
    
    return o;
}

一定要记得根据草的noise采样图对每一个pass进行透明度处理:

代码语言:javascript
复制
    fixed3 noise = tex2D(_FurTex, i.uv.zw * _FurThinness).rgb;
    fixed alpha = clamp(noise - (FURSTEP * FURSTEP) * _FurDensity, 0, 1);

    clip(alpha-_Cutoff);

先给个最简单的纯色看看效果:

再根据FURSTEP附上不同的明暗:

代码语言:javascript
复制
col -= (pow(1 - FURSTEP, 1.2)) * _FurShading;

开始有内味了。

再根据AO贴图给草坪加上AO:

代码语言:javascript
复制
    fixed ambient = saturate((tex2D(_AOTex,i.uv.xy*5).r + tex2D(_AOTex,i.uv.xy*5).g + tex2D(_AOTex,i.uv.xy*5).b)*.357);
    fixed3 ambientTmp = dot(UNITY_LIGHTMODEL_AMBIENT.xyz,(1,1,1))<0.8?UNITY_LIGHTMODEL_AMBIENT.xyz+(1.5,1.5,1.5):UNITY_LIGHTMODEL_AMBIENT;                    
    fixed4 ambientCol = fixed4((ambient * _AOColor * pow(1.5,FURSTEP+2)).rgb,ambient);
    ambientCol.rgb = ambientCol.rgb*(1 - 0.53) + ambientTmp * 0.53;
    col = col*(1 - ambientCol.a) + ambientCol * ambientCol.a;

加上简单的光照:

代码语言:javascript
复制
    fixed shadow = SHADOW_ATTENUATION(i);  
    fixed diffuse = saturate(saturate(dot(worldNormal, worldLight)) * shadow);
    fixed4 diffuseCol = fixed4((diffuse * _LightColor0).rgb + ((1-diffuse) * _ShadowColor * 0.5).rgb,diffuse*pow(1.5,FURSTEP+3));
    col *= diffuseCol;

现在有影子了:

再加上一个简单的specular:

代码语言:javascript
复制
    fixed specular = pow(saturate(dot(worldNormal, worldHalf)), _Shininess * 1.55);
    col *= lerp(0.86,1.4,specular-ambient*0.2);

看着还行,勉强能用

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

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

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

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

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