【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
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章