摘抄自《Unity3D ShaderLab开发实践详解》
光源对物体照明的分类
间接照明
在物体所处的环境中,我们可以把照射到物体上的光源简单地分为直接照明和间接照明。间接照明是光在物体间传播后,最终又对物体形成照明。
直接照明
如果不考虑光线在物体间的传播,也不考虑光线在物体内部的传播,则光线对物体直接照明。
光照模型
Lambert
对于粗糙物体表面的某一点,其亮度应该和入射光线与该点的垂直程度相关,也就是入射光线与此点法线的夹角相关。如果我们用L表示单位长度的入射光线,用C表示到达此点的光线的强度和颜色,用N表示此点的法线,那么物体表面此点的亮度Lum就可以用下面的公式来表示:
Lum = C * max(0, cos<L,N>)
<L,N> 表示的是方向矢量L和N之间的夹角,其cos也就是这两个方向矢量的占积,在实际计算时通过Cg的标准函数库dot(L, N)来完成。这个值对于背向光线的点来说为负,其实就是对其照明为0,因些使用标准函数库中的max(0, value)来对结果进行一些控制。
inline fixed4 LightingLambert(SurfaceOutput s, fixed3 lightDir, fixed atten)
{
fixed diff = max (0, dot( s.Normal, lightDir));
fixed4 c;
// 下面计算了物体表面的纹理颜色、光源颜色以及光源强度的影响
c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
c.a = s.Alpha;
return c;
}
高光类
Phong最基础的,没有算法的
下面我们就来考虑一下上面提到的镜面高光问题,可以很直接地计算某一光线ray在某一法线为normal的点经反射后的光线。如果用R表示光线在此点的单位长反射方向向量,V表示视线的单位方向向量,那么高光部分Spec的计算方式表示为:
Spec = pow ( max (0, cos<R,V>), gloss)
<R,V>表示方向矢量I和N之间的夹角,gloss表示其表面的镜面光滑程度。
以dir = 表面光线 - 光照方向,与视线的点积计算,高光效果
inline fixed4 LightingPhong(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
{
float diff = dot(s.Normal, lightDir);
float3 reflectionVector = normalize(2.0 * s.Normal * diff - lightDir);
float spec = pow( max(0, dot(reflectionVector, viewDir)), _SpecPower);
float3 finalSpec = _SpecularColor.rgb * spec;
fixed4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diff) + (_LightColor0.rgb * finalSpec);
c.a = 1.0;
return c;
}
BlinPhong
通过视线方向和光线方向所形成的半角向量,而不是反射向量来计算光高效果。这种方法已经被证明比Phong在物理计算方面具有更高的精确度。
inline fixed4 LightingBlinPhong(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
{
float3 halfVector = normalize(lightDir + viewDir);
float diff = max (0, dot(s.Normal, lightDir));
float nh = max (0, dot(s.Normal, halfVector));
float spec = pow(nh, _SpecPower) * _SpecularColor;
float4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diff) + (_LightColor0.rgb * _SpecularColor.rgb * spec) * (atten * 2);
c.a = s.Alpha;
return c;
}