Unity Shader - Phong光照模型Shader分析

Phong模型提出了計算鏡面高光的經驗模型,鏡面反射光強與反射光線和視線的夾角a相關:

Ispecular = Ks*Is*(cos a) n

其中

Ks表示物體表面的高光係數

Is表示光強

a表示反射光與視線的夾角

n表示高光指數(注意n爲冪指數,非乘數):n越大,則表面越光滑,反射光越集中,高光範圍越小


定義向量N爲法線向量,向量L爲入射光向量(頂點指向光源),向量R爲反射光向量(頂點指向反射方向),向量V爲視點向量(頂點指向視點方向),如下圖所示:



其中,公式中的cos a可表示爲VR的點積,於是模型公式變爲:

 Ispecular = Ks*Is*(VR) n


向量V是已知的,只需要求出向量R即可。    反射光向量R可以通過入射光向量L和頂點法向量N求出:R = (2LN)N – L

推到過程如下:

以向量L的終點爲起點,向量R的終點爲終點得到向量2P,由向量減法定義可知

2P=R-L (等式1)

同理根據向量減法從圖中可知

P=S-L (等式2)

其中S爲向量L在向量N上的投影,根據向量的投影公式可知

S=(L●N)●N / |N|2  (等式3)

由於此處所使用的向量都爲單位向量,於是上述公式可簡化爲

S=(L●N)●N (等式4)

將等式4代入等式2之後獲得

P=(L●N)●N-L (等式5)

將等式5代入等式1之後獲得

2((L●N)●N-L)=R-L

R=2(L●N)●N-L


接着我們來看下Shader中關於Phong光照函數的具體實現就會豁然開朗:

inline fixed4 LightingPhong (SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
{
// 通過計算反射向量R的公式(R = (2L*N)N – L)來計算出反射向量reflectionVector
float diff = dot(s.Normal, lightDir);
float3 reflectionVector = normalize((2.0 * s.Normal * diff) - lightDir);
// 將反射向量與視點向量進行點乘得到cos a,然後對cos a求specpower次方
float spec = pow(max(0,dot(reflectionVector, viewDir)), _SpecPower);
// 乘以高光顏色,即公式中的高光係數Ks
float3 finalSpec = _SpecularColor.rgb * spec;

fixed4 c;
// 下面公式中的加號前半部分爲漫反射光強,加號後半部分爲phong鏡面反射光強,此處又乘以光源顏色即公式中的光強係數Is
c.rgb = (s.Albedo * _LightColor0.rgb * diff) + (_LightColor0.rgb * finalSpec);
c.a = 1.0;
return c;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章