【UnityShader】漫反射光照模型

蘭伯特光照模型

Cdiffuse = (Clight*Mdiffuse)max(0,n*l)
參數:
  n 表面法線
  I 指向光源的單位矢量
  Mdiffuse 材質的漫反射顏色
  Clight 光源顏色
  max 防止物體被從後面來的光源照亮,CG 提供了這樣的函數 saturate。

函數:saturate(x)描述:把x截取在(0, 1]範圍內,如果x是一個矢量,那麼會對它的每一個分量進行這樣的操作。

半蘭伯特光照模型

Cdiffuse = (Clight*Mdiffuse)(a(n*l)+b)

一般情況下 a,b 均爲 0.5,即

Cdiffuse = (Clight*Mdiffuse)(0.5*(n*l)+0.5)

通過這樣的方式,可以把 n*l 的結果範圍從[-1, 1] 映射到 [0, 1] 範圍內。對於模型的背光面,在原蘭伯特光照模型中點積結果將映射到同一個值,即 0 值處;在半蘭伯特模型中,背光面也可以有明暗變化,不同的點積結果會映射到不同的值上。

優缺點

蘭伯特光照模型-逐頂點光照

缺點:對於一些細分程度較低的模型,逐頂點光照會在背面光與向光面處有一些鋸齒。

蘭伯特光照模型-逐像素光照

優點:可以得到更加平滑的光照效果。
缺點:在光照無法到達的區域,模型的外觀通常是全黑的,沒有任何敏感變化,這會使模型的背光區域看起來就像一個平面一樣,失去了模型細節表現。

半蘭伯特

背光面也會有明暗變化;

代碼實現

// 蘭伯特光照模型-逐頂點光照
Shader "Custom/Shader6_1_diffuse"
{
    Properties
    {
        _Duffuse("Diffuse",color) = (1.0,1.0,1.0,1.0)
    }
    SubShader
    {
        Tags {"LightMode"="ForwardBase"} // 定義該pass在Unity的光照流水線中的角色,只有正確定義LightMode,才能得到Unty內置光照變量
        LOD 200
        
        pass
        {
            CGPROGRAM
            // 漫反射
            #pragma vertex vert 
            #pragma fragment frag 

            #include "Lighting.cginc"

            fixed4 _Duffuse;

            struct a2v{
                float4 position:POSITION; // 頂點座標 
                float3 normal:NORMAL; // 法線
            };
            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 color:COLOR; // 頂點座標
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.position); // 着色器的基本任務

                // 需要把n和l轉換到相同的座標系下。世界空間
                // 從模型空間變換到世界空間,可以使用頂點變換矩陣的逆轉矩陣來對法線進行相同的換算,
                // 從模型空間到世界空間變換矩陣的逆矩陣 unity_WorldToObject,通過調換它在mul中的位置,得到和轉置矩陣相同的矩陣乘法。
                fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 diffuse = _LightColor0.rab * _Duffuse.rgb * saturate(dot(worldNormal, worldLight));
                o.color = ambient + diffuse;
                return o;
            }

            fixed4 frag(v2f v):SV_Target
            {
                return fixed4(v.color, 1.0);
            }

            ENDCG
        }
    }
    FallBack "Diffuse"
}
// 蘭伯特光照模型-逐像素光照
Shader "Custom/Shader6_1_diffuse"
{
    Properties
    {
        _Diffuse("Diffuse",color) = (1.0,1.0,1.0,1.0)
    }
    SubShader
    {
        Tags {"LightMode"="ForwardBase"} 
        LOD 200
        
        
        pass
        {
            CGPROGRAM
            // 漫反射
            #pragma vertex vert 
            #pragma fragment frag 

            #include "Lighting.cginc"

            fixed4 _Diffuse;

            struct a2v
            {
                float4 position:POSITION;
                float3 normal:NORMAL;
            };
            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 nor:TEXCOORD0; // 法線
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.position); // 頂點座標變換到裁剪空間
                o.nor = v.normal;
                return o;
            }

            fixed4 frag(v2f v):SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal = normalize(mul(v.nor, (fixed3x3)unity_WorldToObject));
                fixed3 worldLight = normalize(_WorldSpaceLightPos0);
                fixed3 diffsue = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
                return fixed4(ambient + diffsue, 1.0);
            }
            ENDCG
        }
       
    }
    FallBack "Diffuse"
}
//半蘭伯特
Shader "ZJT/Shader06-half"
{
    Properties
    {
        _Diffuse ("Diffuse", Color) = (1.0, 1.0, 1.0, 1.0)
    }
    SubShader
    {
        Tags{"RenderType"="Opaque"}
        LOD 200

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

            #include "Lighting.cginc"

            fixed4 _Diffuse;

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

            struct v2f
            {
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            fixed4 frag(v2f v):SV_Target
            {
                fixed3 worldNormal = normalize(v.worldNormal);
                fixed3 worlfLightDir = normalize(_WorldSpaceLightPos0.xyz);

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (0.5 + 0.5 * dot(worldNormal, worlfLightDir));
                return fixed4(ambient + diffuse, 1);
            }
            ENDCG
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章