Unity Shader Gradient Texture Summary

Posted by BluePhoenixNC on Mon, 05 Aug 2019 05:18:34 +0200

Unity Shader's Essential Reading Notes - Preliminary Chapter - Chapter 7 - Gradual Texture

Summary

Gradient texture is mostly used in cartoon style rendering. Gradient texture can control tone gradient to achieve the effect of tone change. The contour formed by this method is more obvious than the traditional diffuse reflection. The gradient texture we use here is a two-dimensional texture, which records the gradient of tone. Different gradient textures provide different tone gradient schemes, which can form different artistic styles.

Code Details

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unity Shaders Book/Chapter 7/Ramp Texture"{
    Properties{
        _Color ("Color Tint",Color)=(1,1,1,1)
        _RampTex ("Ramp Tex",2D)="white" {}
        _Specular ("Specular",Color)=(1,1,1,1)
        _Gloss ("Gloss",Range(8.0,256))=20
    }
    SubShader{
        pass{
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"

            fixed4 _Color;
            sampler2D _RampTex;
            float4 _RampTex_ST;
            fixed4 _Specular;
            float _Gloss;

            struct a2v{
                float4 vertex:POSITION;
                float3 normal:NORMAL;
                float4 texcoord:TEXCOORD0;
            };

            struct v2f{
                float4 pos:SV_POSITION;
                float3 worldNormal:NORMAL;
                float3 worldPos:TEXCOORD1;
                float2 uv:TEXCOORD2;
            };

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

                o.worldNormal=UnityObjectToWorldNormal(v.normal);

                o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;

                o.uv=v.texcoord.xy*_RampTex_ST.xy+_RampTex_ST.zw;

                return o;
            }

            fixed4 frag(v2f i):SV_TARGET{
                fixed3 worldNormal=normalize(i.worldNormal);
                fixed3 worldLightDir=UnityWorldSpaceLightDir(i.worldPos);
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;

                fixed halfLambert=0.5*dot(worldNormal,worldLightDir)+0.5;
                //fixed3 diffuseColor=((tex2D(_RampTex,fixed2(halfLambert,halfLambert)).rgb+tex2D(_RampTex,i.uv).rgb)/2)*_Color.rgb;
                fixed3 diffuseColor=tex2D(_RampTex,fixed2(halfLambert,halfLambert)).rgb*_Color.rgb;
                fixed3 diffuse=_LightColor0.rgb*diffuseColor;

                fixed3 viewDir=normalize(UnityWorldSpaceViewDir(i.worldPos));
                fixed3 halfDir=normalize(viewDir+worldLightDir);
                fixed3 specular=_LightColor0.rgb*_Specular.rgb*pow(max(0,dot(worldNormal,halfDir)),_Gloss);

                return fixed4(ambient+diffuse+specular,1.0);
            }
            ENDCG
        }
    }
    Fallback "Specular"
}

There's only one place to pay special attention to this code, and there's not much difference between other places before:
fixed3 diffuseColor=tex2D(_RampTex,fixed2(halfLambert,halfLambert)).rgb*_Color.rgb;
This line of code samples the gradient texture.
The gradient texture we use is as follows:



We can find that all gradient textures are essentially one-dimensional textures, which only change horizontally. So the half Lambert parameter is used for sampling, so that the gradient of tone is linked to the diffuse reflection.
The final results are as follows:



Note that due to the Wrap Mode settings, on some model surfaces, due to the problem of floating point accuracy, although halfLambert maximum value is 1, it may appear as 1.0001. At this time, Wrap Mode will lead to completely different sampling results (the color at both ends of the gradient texture is very different), so it will produce defects. This situation is usually caused by the Repeat pattern, as shown in the figure:

At this point, we just need to change to Clamp.

Topics: Unity Fragment