就我目前所知道的,在光照这吧,主要有三种算法,第一种漫反射的Lambert已经介绍过了,接下来还有BlinnPhong和Phong,都是用来做高光的.
那么我们先来看第一种,先看代码
- BlinnPhong光照模型
inline float4 LightingSpecular(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); fixed4 c; c.rgb=(s.Albedo*_LightColor0.rgb*diff+_LightColor0.rgb*_Specular.rgb*spec)*(atten*2); c.a=s.Alpha+_LightColor0.a*_Specular.a*spec*atten; return c; }
在上述代码中,光照模型中参数使用了相机的方向(viewDir,使用这种类型的函数原型的时候, unity 会自动认出我们需要的是相机方向,因此会从外部把相机方向作为参数传进 shader)。光照模型的第一行代码是经典的BlinnPhong模型算法,通过相机方向和入射方向算出一个"中间向量"(向量加法的平行四边形原则,可以得到另外一个向量,即对角线),最后通过这个中间方向和点的法线的夹角来决定我们的相机看到的光照强度.
- surf函数
void surf(Input In,inout SurfaceOutput o){ half4 c=tex2D(_MainTex,In.uv_MainTex)* _Tint; o.Alpha=c.a; o.Albedo=c.rgb; o.Specular=_SpecularPower; }
在surf函数中,我们设定了Specular的值为_SpecularPower来供用户调整.
- Phong模型
这个模型是更贴近认知的一种计算方法,效果比BlinnPhong平滑,但是计算消耗大.
代码:
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)),s.Specular); float finalSpec=_Specular.rgb*spec; fixed4 c; c.rgb=s.Albedo*_LightColor0.rgb*diff+(_LightColor0.rgb*finalSpec); c.a=1.0; return c; }
这种计算方法是用了反射方向与相机方向的点积做了幂运算得到的.
- 效果图:
BlinnPhong
Phong
移动的时候会感觉出高光位置的变化