Contents

渐变纹理

渐变纹理是用来做什么的

渐变纹理的主要作用是可以让模型呈现出插画、卡通风格的渲染效果


渐变纹理的基本原理

利用半兰伯特光照公式后半部分计算出来的0~1之间的值,构建一个UV相同的 坐标,然后从渐变纹理中取出对应的颜色进行叠加

决定漫反射明暗的不再是由 0~1这个值决定而是由渐变纹理中取出的颜色进行叠加达到最终效果

fixed halfLarbertNum = 0.5 + dot(wNormal,lightDir) * 0.5;
fixed3 rampColor = _LightColor0.rgb * _MainColor.rgb * tex2D(_RampTex,fixed2(halfLarbertNum,halfLarbertNum));

修改渐变纹理设置 避免黑点出现

避免渐变纹理接缝处有黑点

我们需要将 Wrap Mode(循环模式)切换为 Clamp(拉伸模式)

出现黑点的原因是:

  • 浮点数计算可能存在误差,会出现超过1的值(1.00001)
  • 如果使用Repeat(重复模式),会舍弃整数部分,保留小数0.00001
  • 这时对应的颜色会是最左边的值,因此会出现黑色

渐变纹理的基本实现

Shader "Unlit/Gradient"
{
    Properties
    {
        _MainColor("MainColor",Color) = (1,1,1,1)
        _RampTex("RampTex",2D) = ""{}
        _SpecularColor("SpecularColor", Color) = (1,1,1,1)
        _SpecularNum("SpecularNum", Range(8, 256)) = 18
    }
    SubShader
    {
        
        Pass
        {
            Tags { "LightMode" ="ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"


            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 normal:NORMAL;
                float4 wpos : TEXCOORD1;
            };

            sampler2D _RampTex;
            float4 _RampTex_ST;
            fixed4 _MainColor;
            fixed4 _SpecularColor;
            float _SpecularNum;

            v2f vert (appdata_base v)
            {
                v2f data;
                data.vertex = UnityObjectToClipPos(v.vertex);
                data.normal = UnityObjectToWorldNormal(v.normal);
                data.wpos = mul(unity_ObjectToWorld,v.vertex);
                return data;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 wNormal = normalize(i.normal);
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed halfLarbertNum = 0.5 + dot(wNormal,lightDir) * 0.5;
                fixed3 rampColor = _LightColor0.rgb * _MainColor.rgb * tex2D(_RampTex,fixed2(halfLarbertNum,halfLarbertNum));

                //Phong
                float3 viewDir = normalize(_WorldSpaceCameraPos - i.wpos);
                float3 halfDir = normalize(lightDir + viewDir);
                fixed3 specularColor = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0,dot(wNormal,halfDir)),_SpecularNum);

                fixed3 color = UNITY_LIGHTMODEL_AMBIENT.rgb + rampColor + specularColor;
                return fixed4(color,1);
            }
            ENDCG
        }
    }
}

渐变纹理综合实现

Shader "Unlit/Gradient2"
{
    Properties
    {
        _MainTex("MainTex",2D) = ""{} //主贴图
        _NormalTex("NormalTex",2D) = ""{} //法线贴图
        _BumpScale("BumpScale",range(0,1)) = 1 //凹凸度
        _DiffuseColor("DiffuseColor",Color) = (1,1,1,1) //漫反射颜色
        _RampTex("RampTex",2D) = ""{} //渐变贴图
        _SpecularColor("SpecularColor", Color) = (1,1,1,1) //高光反射颜色
        _SpecularNum("SpecularNum", Range(8, 256)) = 18 //光泽度
    }
    SubShader
    {
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"
         
            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 uv : TEXCOORD0;
                float4 wpos : TEXCOORD1;
                float3 viewDir:TEXCOORD2;
                float3 lightDir:TEXCOORD3;
            };

            //漫反射
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _DiffuseColor;
            sampler2D _RampTex;
            //法线
            sampler2D _NormalTex;
            float4 _NormalTex_ST;
            float _BumpScale;
            //高光反射
            fixed4 _SpecularColor;
            float _SpecularNum;


            v2f vert (appdata_full v)
            {
                v2f data;
                //坐标转换
                data.pos = UnityObjectToClipPos(v.vertex);
                data.wpos = mul(unity_ObjectToWorld,v.vertex);
                //uv贴图
                data.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                data.uv.zw =  v.texcoord.xy * _NormalTex_ST.xy + _NormalTex_ST.zw;
                //计算 切线空间 变换矩阵
                float3 bitangent = cross(v.tangent.xyz,v.normal) * v.tangent.w;
                float3x3 rotation = float3x3(v.tangent.xyz,bitangent,v.normal);
                //切线空间下的 视角和灯光向量
                data.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex));
                data.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex));
                return data;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //法线
                float4 packedNoraml = tex2D(_NormalTex,i.uv.zw);
                float3 unpackNormal = UnpackNormal(packedNoraml);
                //凹凸度
                unpackNormal.xy *= _BumpScale;
                unpackNormal.z = sqrt(1 -saturate(dot(unpackNormal.xy,unpackNormal.xy)));
                //漫反射
                fixed3 uvColor = tex2D(_MainTex,i.uv.xy) * _DiffuseColor.rgb;
                fixed halfLarbertNum = dot(i.lightDir,unpackNormal) * 0.5 + 0.5;//渐变贴图
                fixed3 diffuseColor = _LightColor0 * uvColor * tex2D(_RampTex,fixed2(halfLarbertNum,halfLarbertNum));
                //高光
                float3 halfDir = normalize(i.viewDir + i.lightDir);
                fixed3 specularColor = _LightColor0 * _SpecularColor * pow(max(0,dot(halfDir,unpackNormal)),_SpecularNum);
                //blinn-phong
                fixed3 blinnPhongColor = UNITY_LIGHTMODEL_AMBIENT * uvColor + diffuseColor + specularColor;
                return fixed4(blinnPhongColor,1);
            }
            ENDCG
        }
    }
}