蘭伯特光照模型
n 表面法線
I 指向光源的單位矢量
Mdiffuse 材質的漫反射顏色
Clight 光源顏色
max 防止物體被從後面來的光源照亮,CG 提供了這樣的函數 saturate。
函數:saturate(x)描述:把x截取在(0, 1]範圍內,如果x是一個矢量,那麼會對它的每一個分量進行這樣的操作。
半蘭伯特光照模型
一般情況下 a,b 均爲 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
}
}
}