使用噪声纹理制作消融效果

  1. 噪声纹理(一张灰度图)采样得到其中噪声值(rgb中其中一个就行),使用这个值进行alphaTest或者其他用途
  2. 使用了一个过渡色,即将消融与不消融之间的过渡颜色,具体原理在代码中有注释
  3. 阴影的特殊处理,因为消融后不应该再投射阴影,所以必须要自己定义“LightMode” = “ShadowCaster”阴影投射pass,得到正确的阴影投射图。
Shader "FFD/15/Dissolve"
{
    Properties
    {
        _BurnAmount("Burn Amount",range(0.0,1.0)) = 0.0
        _LineWidth("Burn Line Width",range(0.0,0.2)) = 0.1
        _BumpScale ("Bump Scale",range(-1,1)) = 0
        _MainTex("Main Tex",2D) = "white"{}
        _BumpTex("Bump Map",2D) = "bump"{}
        _BurnTex("Burn Map",2D) = "white"{}
        _BurnFirstColor("Burn First Color",Color) = (1,1,1,1)
        _BurnSecondColor("Burn Second Color",Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
    

        Pass
        {
            cull off
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
        
            #pragma multi_compile_fwardbase
            
            #include "UnityCG.cginc"
            #include "autolight.cginc"
            #include "lighting.cginc"

            struct v2f
            {
                float2 mainUV : TEXCOORD0;
                float2 bumpUV : TEXCOORD1;
                float2 burnUV : TEXCOORD2;
                float3 worldNormal : NORMAL;
                float4 TtoW0 : TEXCOORDD3;
                float4 TtoW1 : TEXCOORD4;
                float4 TtoW2 : TEXCOORD5;
                float4 pos : SV_POSITION;
                SHADOW_COORDS(6)
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _BumpTex;
            float4 _BumpTex_ST;
            sampler2D _BurnTex;
            float4 _BurnTex_ST;
            float _BurnAmount;
            float _LineWidth;
            float _BumpScale;
            fixed4 _BurnFirstColor;
            fixed4 _BurnSecondColor;


            v2f vert (appdata_full v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);

                o.mainUV = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.bumpUV = TRANSFORM_TEX(v.texcoord, _BumpTex);
                o.burnUV = TRANSFORM_TEX(v.texcoord, _BurnTex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                float3 biNormal = cross(v.normal,v.tangent.xyz)*v.tangent.w;
                float3 biNormalWorld = UnityObjectToWorldDir(biNormal);

                float3 tangentWorld = UnityObjectToWorldDir(v.tangent);

                float4 worldPos = mul(unity_ObjectToWorld,v.vertex);

                o.TtoW0 = float4(tangentWorld.x,biNormalWorld.x,o.worldNormal.x,worldPos.x);
                o.TtoW1 = float4(tangentWorld.y,biNormalWorld.y,o.worldNormal.y,worldPos.y);
                o.TtoW2 = float4(tangentWorld.z,biNormalWorld.z,o.worldNormal.z,worldPos.z);


                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.mainUV);

                fixed3 burn = tex2D(_BurnTex,i.burnUV).rgb;

                clip(burn.g-_BurnAmount);

                float3x3 tanToWorld = float3x3(i.TtoW0.xyz,i.TtoW1.xyz,i.TtoW2.xyz);

                float4 worldPos = float4(i.TtoW0.w,i.TtoW1.w,i.TtoW2.w,1);

                float3 norBump = UnpackNormal(tex2D(_BumpTex,i.bumpUV));
                norBump.xy = norBump.xy * _BumpScale;
                norBump.z = sqrt(1-saturate(dot(norBump.xy,norBump.xy)));

                float3 worldNormal = normalize(mul(tanToWorld,norBump));

                float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * col;

                fixed3 diffuse = _LightColor0.xyz * saturate(dot(worldNormal,worldLight)) * col;

//              UNITY_LIGHT_ATTENUATION(atten,i,worldPos);
                float shadow = SHADOW_ATTENUATION(i);

                float t = 1-smoothstep(0,_LineWidth,(burn.r-_BurnAmount));

                //如果t为1的话说明当前像素马上要被灼烧掉此时颜色应该很红,如果为0的话说明还要等BurnAmount的值增加到1才灼烧,此时颜色应该很淡
                //如果t为0说明burn.r-_BurnAmount>_LineWidth;也就是说amount还没怎么增长,此时burnColor全为第一个颜色
                fixed4 burnColor = lerp(_BurnFirstColor,_BurnSecondColor,t);

//              burnColor = pow(burnColor,5);
                
                fixed3 finalColor = lerp(ambient+diffuse*shadow,burnColor.xyz,t*step(0.001,_BurnAmount));

                return fixed4(finalColor,1);
//              fixed testSmooth = smoothstep(0.5,0.6,0.655);
//              return fixed4(testSmooth,testSmooth,testSmooth,testSmooth);
//              return fixed4(0.655,0.655,0.655,0.655);
            }
            ENDCG
        }

        Pass
        {
            Tags{"LightMode" = "ShadowCaster"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #pragma multi_compile_shadowcaster

            #include "unitycg.cginc"
            #include "autolight.cginc"
            #include "lighting.cginc"

            float _BurnAmount;
            sampler2D _BurnTex;
            float4 _BurnTex_ST;


            struct v2f{
                //系统定义的宏,包含了阴影投射需要的变量值
                V2F_SHADOW_CASTER;
                float2 uv : TEXCOORD0;
            };

            v2f vert(appdata_base v)
            {
                v2f o;
                //计算得到上面宏定义好的变量值
                TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);
                o.uv = TRANSFORM_TEX(v.texcoord,_BurnTex);
                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 burn = tex2D(_BurnTex,i.uv).rgb;
                clip(burn.r-_BurnAmount);
                //完成阴影投射
                SHADOW_CASTER_FRAGMENT(i);
            }


            ENDCG
        }

    }
    FallBack "Diffuse"
}

你可能感兴趣的:(使用噪声纹理制作消融效果)