UnityShader入门精要学习笔记(九):基础纹理之渐变纹理与遮罩纹理

时间:2021-01-25 10:23:08

一.渐变纹理

利用半兰伯特构建float2变量,以此对一张渐变纹理进行采样。漫反射的颜色靠此方式获得。

Shader "Custom/Edu/RampTexture" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        //_MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Specular("Specular",Color) = (1,1,1,1)
        _RampTex("Ramp Texture",2D) = "white"{}
        _Gloss("Gloss",Range(9,256)) = 40
    }
    SubShader {
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _Color;
            //sampler2D _MainTex;
            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:TEXCOORD0;
                float3 worldPos:TEXCOORD1;
                //float2 uv:TEXCOORD2;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                o.worldNormal = mul(v.normal,(float3x3)_World2Object);
                o.worldPos = mul((float3x3)_Object2World,v.vertex);
                //o.uv = TRANSFORM_TEX(v.texcoord,_RampTex);
                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                float3 worldNormal = normalize(i.worldNormal);

                float3 worldLightDir = normalize( UnityWorldSpaceLightDir(i.worldPos) );

                float halfLambert = dot(worldNormal,worldLightDir) * 0.5 + 0.5;

                fixed3 diffuseColor = tex2D(_RampTex,float2(halfLambert,halfLambert)).rgb;

                fixed3 diffuse = diffuseColor * _LightColor0.rgb;

                float3 worldViewDir = UnityWorldSpaceViewDir(i.worldPos);

                float3 halfDir = normalize(worldViewDir + worldLightDir);

                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow( saturate(dot(worldNormal,halfDir)), _Gloss);

                return fixed4(ambient + diffuse + specular, 1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

效果图:

UnityShader入门精要学习笔记(九):基础纹理之渐变纹理与遮罩纹理

二.遮罩纹理

这遮罩纹理的使用是对高光效果进行遮罩,使用同一组uv坐标,对同一位置处的遮罩纹理进行采样,这里只使用了r分量。
同样,可以分为切线空间下计算以及世界空间下计算。

1.切线空间下的高光遮罩纹理实现:

Shader "Custom/Edu/MaskTexTangent" {

    Properties
    {
        _MainTex("MainTex",2D) = "white"{}
        _BumpMap("BumpMap",2D) = "white"{}
        _BumpScale("BumpScale",float) = 1
        _SpecularMask("SpecularMask",2D) = "white"{}
        _Specular("Specular",Color) = (1,1,1,1)
        _Color("ColorTint",Color) = (1,1,1,1)
        _Diffuse("DIffuse",Color) = (1,1,1,1)
        _SpecularScale("SpecularScale",float) = 1.0
        _Gloss("Gloss",Range(8,256)) = 8
    }

    SubShader
    {
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            sampler2D _MainTex;float4 _MainTex_ST;
            sampler2D _SpecularMask;float4 _SpecularMask_ST;
            sampler2D _BumpMap;float4 _BumpMap_ST;
            float _BumpScale;
            fixed4 _Specular;
            fixed4 _Color;
            fixed4 _Diffuse;
            float _Gloss;
            float _SpecularScale;

            struct a2v
            {
                float4 vertex:POSITION;
                float3 normal:NORMAL;
                //注意因为我们要使用tangent的w分量,所以这里的类型是float4
                float4 tangent:TANGENT;
                float4 texcoord:TEXCOORD0;
            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                float2 uv:TEXCOORD0;
                float3 viewDir:TEXCOORD1;
                float3 lightDir:TEXCOORD2;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                float3 bionormal = cross(normalize(v.normal),normalize(v.tangent.xyz))*v.tangent.w;
                //float3x3是一种类型,不需要类型转换时不用加括号
                float3x3 rotation = float3x3(v.tangent.xyz,bionormal,v.normal);

                //or just use TANGENT_SPACE_ROTATION;
                //注意,注意取xyz分量
                o.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex)).xyz;
                o.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex)).xyz;

                //o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
                //o.uv.zw = v.texcoord.xy * _BumpTex_ST.xy + _BumpMap_ST.zw;
                o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
                //o.uv.zw = TRANSFORM_TEX(v.texcoord,_BumpMap);

                return o;
            }
            fixed4 frag(v2f i):SV_Target
            {
                float3 tangentViewDir = normalize(i.viewDir);
                float3 tangentLightDir = normalize(i.lightDir);

                //使用的是fixed3类型
                fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap,i.uv));
                tangentNormal.xy *= _BumpScale;
                tangentNormal.z = sqrt(1.0-saturate(dot(tangentNormal.xy,tangentNormal.xy)));

                fixed3 albedo = tex2D(_MainTex,i.uv).rgb * _Color.rgb;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;

                //半兰伯特模型
                //fixed3 halfLambert = dot(tangentNormal,tangentLightDir) * 0.8 + 0.2;
                //fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;

                fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse * saturate(dot(tangentNormal,tangentLightDir));

                //潜意识中的错误写法,误以为和渐变纹理的使用方式一样?!
                fixed3 halfDir = normalize(tangentViewDir + tangentLightDir);
                //fixed3 maskColor = tex2D(_MaskTex,float2(halfDir,halfDir)).rgb;
                //正确写法:通过uv对MaskTex对应位置进行采样!!!
                //fixed3 specularMask = tex2D(_MaskTex,i.uv.xy).rgb * _SpecularScale;
                //不好意思上面仍然不是正确的写法
                //所谓的 specularMask 实际上只利用采样纹理的一个分量通道,这里仅仅利用r。
                fixed specularMask = tex2D(_SpecularMask,i.uv).r * _SpecularScale;
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(tangentNormal,halfDir)),_Gloss) * specularMask;

                return fixed4(ambient + diffuse + specular,1.0);
            }

            ENDCG
        }
    }
}

2.世界空间下高光遮罩纹理实现:

Shader "Custom/Edu/MaskTexWorld" {
    Properties {
        _Color ("ColorTint", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Gloss ("Gloss", Range(8,256)) = 20
        _BumpMap("BumpMap",2D) = "white"{}
        _BumpScale("BumpScale",Range(-1,1)) = 1
        _Specular("Specular",Color) = (1,1,1,1)
        _SpecularMask("SpecularMask",2D) = "white"{}
        _SpecularScale("SpecularScale",float) = 1.0

    }
    SubShader {
        Pass
        {
            Tags{"LgihtMode" = "ForwarBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Gloss;
            sampler2D _BumpMap;
            float _BumpScale;
            fixed4 _Specular;
            sampler2D _SpecularMask;
            float _SpecularScale;

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

            struct v2f
            {
                float4 pos:SV_POSITION;
                float4 TtoW0:TEXCOORD0;
                float4 TtoW1:TEXCOORD1;
                float4 TtoW2:TEXCOORD2;
                float2 uv:TEXCOORD3;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                //需要归一化么?(其实返回的结果已经归一化了)
                float3 worldNormal = normalize( UnityObjectToWorldNormal(v.normal) );
                float3 worldTangent = normalize( UnityObjectToWorldDir(v.tangent.xyz) );
                float3 worldBionormal = cross(worldNormal,worldTangent)*v.tangent.w;

                float3 worldPos = mul(_Object2World,v.vertex);
                o.TtoW0 = float4(worldTangent.x,worldBionormal.x,worldNormal.x,worldPos.x);
                o.TtoW1 = float4(worldTangent.y,worldBionormal.y,worldNormal.y,worldPos.y);
                o.TtoW2 = float4(worldTangent.z,worldBionormal.z,worldNormal.z,worldPos.z);

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

                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {

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

                //为啥老是忘记归一化呢
                float3 worldLightDir =normalize(UnityWorldSpaceLightDir(worldPos));
                //为啥老是忘记归一化呢
                float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));

                float3 bump = UnpackNormal(tex2D(_BumpMap,i.uv));

                bump.xy *= _BumpScale;

                bump.z = sqrt(1-saturate(dot(bump.xy,bump.xy)));

                float3 worldNormal = normalize( float3(dot(bump,i.TtoW0.xyz),dot(bump,i.TtoW1.xyz),dot(bump,i.TtoW2.xyz)) );

                fixed3 albedo = tex2D(_MainTex,i.uv).rgb;

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;

                fixed3 diffuse = _LightColor0.rgb * albedo * saturate(dot(worldNormal,worldLightDir));

                fixed specularMask = tex2D(_SpecularMask,i.uv).r * _SpecularScale;

                fixed3 halfDir = normalize(worldLightDir + worldViewDir);

                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal,halfDir)),_Gloss) * specularMask;

                return fixed4(ambient + diffuse + specular,1.0);
            }



            ENDCG
        }
    }
    FallBack "Diffuse"
}

3.效果图:

UnityShader入门精要学习笔记(九):基础纹理之渐变纹理与遮罩纹理

两种方式看不出任何差别。