逐頂點計算漫反射光照
蘭伯特模型計算方法
以下是在頂點着色器中使用蘭伯特光照模型計算漫反射光照的shader代碼:
Properties
{
_Diffuse("Diffuse", Color) = (1.0, 1.0, 1.0, 1.0)
}
SubShader
{
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 position : SV_POSITION;
float3 color : COLOR;
};
v2f vert(a2v a)
{
v2f v;
v.position = UnityObjectToClipPos(a.vertex);
//環境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//世界座標下的法線
fixed3 worldNormal = normalize(mul(a.normal, (float3x3)unity_WorldToObject));
//光源光照顏色和強度
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//漫反射顏色和強度
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
v.color = ambient + diffuse;
return v;
}
fixed4 frag(v2f a) : SV_Target
{
return fixed4(a.color, 1.0);
}
ENDCG
}
}
UnityObjectToClipPos方法是Unity內置的方法,它的主要作用就是把頂點座標從模型空間轉換到裁剪空間中,它完成了模型->世界->投影矩陣的座標變換。
UNITY_LIGHTMODEL_AMBIENT也是Unity內置變量,用來獲取環境光。
unity_WorldToObject是模型空間到世界空間的變換矩陣的逆矩陣,將它作爲mul函數中的第二個參數是爲了得到和轉置矩陣相同的矩陣乘法。由於法線是三維向量,還要通過float3x3截取它的前三行前三列。
_WorldSpaceLightPos0是Unity內置的一個光源變量,但它只有在場景中只有一個光源並且該光源是平行光的時候纔是可用的。
_LightColor0是Unity內置的光源顏色和強度信息,它和LightMode是否正確定義有關。
saturate(x)函數是CG中的內置函數,它的作用和max一樣。x參數可以是標量,也可以是矢量,如果是矢量,會對它每一個分量進行這樣的操作。
半蘭伯特模型計算方法
//漫反射顏色和強度
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
半蘭伯特模型只需要將上面代碼中的saturate(dot(worldNormal, worldLight))替換爲dot(worldNormal, worldLight)*0.5+0.5 即可。
逐像素光照###
蘭伯特模型計算方法####
以下是在片元着色器中使用蘭伯特光照模型計算漫反射光照的shader代碼:
Properties
{
_Diffuse("Diffuse", Color) = (1.0, 1.0, 1.0, 1.0)
}
SubShader
{
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 position : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
v2f vert(a2v a)
{
v2f v;
v.position = UnityObjectToClipPos(a.vertex);
//把法線轉化爲世界座標下的法線
v.worldNormal = normalize(mul(a.normal, (float3x3)unity_WorldToObject));
return v;
}
fixed4 frag(v2f a) : SV_Target
{
//環境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//光照
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//漫反射光
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(a.worldNormal, worldLight));
//顏色
fixed3 color = ambient + diffuse;
return fixed4(color, 1.0);
}
ENDCG
}
}
在片元着色其中計算光照時,頂點着色器只需要把世界空間座標下的法線傳遞給片元着色器,在片元着色器中完成後續計算即可,計算方法和在頂點着色器中計算一樣。
半蘭伯特模型計算方法
同上……