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;
}


猜你喜欢

转载自blog.csdn.net/chunxiao860815/article/details/50311331