在Shader中实现BlinnPhong光照时,会用到一些代码,这些代码令人费解,下面是BlinnPhong 在Unity里内置的函数:
在文件Lighting.cginc里面
windows系统下位于:
…Unity\Editor\Data\CGIncludes\
这个是实现BlinnPhong 的函数
inline fixed4 LightingBlinnPhong (SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) { half3 h = normalize (lightDir + viewDir); fixed diff = max (0, dot (s.Normal, lightDir)); float nh = max (0, dot (s.Normal, h)); float spec = pow (nh, s.Specular*128.0) * s.Gloss; fixed4 c; c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2); c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten; return c; }
我们先来了解一下光照的计算。
光照是由发射光,环境光,漫反射光以及镜面高光组成的,这四个部分先单独运算,然后再累积起来组成最终的效果。
一 发射光:
openGL 中物体材质设置发射颜色来模拟发射光的
发射颜色 = 物体发射材质颜色
二 漫反射:
漫反射颜色 = 光源的漫反射光颜色x物体的漫反射材质颜色x diff
其中漫反射因子diff是光线与定点法线向量的点积:
diff = max(0,dot(N,L))
PS: dot() 为两个向量之间的的cos值.很直观的展示的漫反射的规律.在正对着入射光线时光照最强,在大于等于90度时候,没有反射的效果.
三 环境光:
环境颜色 = 光源的环境光颜色 x 物体的环境材质颜色
四 镜面反射:
镜面反射颜色 = 光源的镜面光颜色x物体的镜面材质颜色 x spec
spec =power(max(0,dot(s.Normal, h)),shininess)
这里的shininess是128
h = normalize (lightDir + viewDir)
h向量是视线向量viewDir 与光线向量lightDir的半向量,几何意义就是视线与光线夹角的平分线.
这里的normalize()函数用于获取lightDir + viewDir 坐标转化为单位向量,且方向不变.
光照的终极公式:
光照颜色 = 反射颜色 +全局环境颜色 +(环境颜色 + 漫反射颜色 +镜面反射颜色) x 聚光灯效果 x 衰弱因子
这里给的物体是不发光的,没有反射颜色这的部分.
half3 h = normalize (lightDir + viewDir); //h向量是视线向量viewDir 与光线向量lightDir的半向量,几何意义就是视线与光线夹角的平分线. fixed diff = max (0, dot (s.Normal, lightDir)); //漫反射因子diff是光线与定点法线向量的点积,大于等于90度,没有反射的效果. float nh = max (0, dot (s.Normal, h)) //nh 是h向量与定点法线向量的点积 float spec = pow (nh, s.Specular*128.0) * s.Gloss; //得到nh 向量进行s.Specular*128.0 次乘方计算 fixed4 c; // 光照颜色 = 反射颜色 +全局环境颜色 +(环境颜色 + 漫反射颜色 +镜面反射颜色) x 聚光灯效果 x 衰弱因子 c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2);//漫反射 + 镜面反射 c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten;