Lambert漫反射光照模型,这是一个用来模拟粗糙表面对光线的漫反射现象的经验模型,对于纸张、粗糙墙壁等等来说,这个模型或许够用,但对于金属这样的光滑表面来说,我们就需要使用Phong模型来模拟光滑表面对光线的镜面反射现象。同Lambert一样,这个模型也是经验模型,而且在程序中,我们经常同时使用Lambert和Phong两个模型,因为在现实世界中,任何表面都会同时发生漫反射和镜面反射两种现象,因此我们就要使用两种模型分别计算两种反射后的光强(也就是顶点颜色值),是渲染的效果看起来真实一些。但要注意,这样做并不会带来真正真实的渲染效果,毕竟这两种模型都是经验模型,考虑的都是理想情况下。而Blinn-phong光照模型是基于Phong的修正模型。
设顶点的单位法向量为N,有公式:
R + L = (2N • L)N (这里再次提醒一下,L的方向是由顶点指向光源的)
由这个可以推出:
R = (2N • L)N - L
因此Phong的公式如下图左图所示。
Shader "Study/7_Phong" {Properties{_Color("Main Color", Color) = (1,1,1,1)_SpecColor("Specular Color", Color) = (0.5, 0.5, 0.5, 1)// 高光颜色_Shininess("Shininess", Range(0.01, 1)) = 0.078125// 高光指数【光泽度】_MainTex("Base (RGB) Gloss (A)", 2D) = "white" {}}SubShader{Tags{ "RenderType" = "Opaque" }LOD 300CGPROGRAM
#pragma surface surf BlinnPhongTest// 半角向量和BilnnPhong:使用入射光线和视线的中间平均值,即半角向量,然后使用该半角和法线计算出一个和视角相关的高光。// 相关参数:【lightDir点到光源单位向量】【viewDir点到摄像机单位向量】【atten衰减系数】【_LightColor0场景中平行光的颜色】float4 LightingBlinnPhongTest(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten){// 1.半角向量:求(点到光源+点到摄像机)的单位向量,他们的中间平均值float3 h = normalize(lightDir + viewDir);// 2.漫反射系数【点到光源单位向量与法线向量的余弦值】float diff = max(0, dot(s.Normal, lightDir));// 3.反射向量float3 r = 2 * dot(s.Normal, lightDir) * s.Normal - lightDir;// 4.高光底数【反射向量与视角向量的余弦值】float re = max(0, dot(r, viewDir));// 5.高光系数:根据高光低数和高光指数求得float spec = pow(re, s.Specular * 256) * s.Gloss;float4 c;// 6.最终光照rgb = 漫反射+半角高光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;}sampler2D _MainTex; // 主材质fixed4 _Color; // 主材质颜色half _Shininess; // 高光指数struct Input {float2 uv_MainTex; // 主材质的UV信息};void surf(Input IN, inout SurfaceOutput o) {// 取主纹理的对应当前像素点的值fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);// Albedo反照率,即物体反射光的数量与外来光数量的比值。// Albedo = 主纹理 x 主色调,反映了物体的基色,与任何光相关的信息(比如diffuse, shiness等)无关o.Albedo = tex.rgb * _Color.rgb; // 颜色纹理=主纹理*主材质颜色// Gloss光滑度[0, 1],用于控制反射的模糊程度,值越大,高光反射越清晰,反之则越模糊,0将无高光效果。// 光滑度的“滑”是面的概念,代表物体整体的光滑程度// 比如说,同样一块金属,在它生锈的过程中,其反射就会慢慢变弱,可以通过Gloss值控制// 实际上它是针对高光计算结果的附加系数o.Gloss = tex.a;o.Alpha = tex.a * _Color.a; // 透明度// Shininess光泽度[0, 1],又叫高光指数或镜面反射指数,注意,它在SurfaceOutput结构中的命名(Specular)很容易让人误解为它是高光强度,其实不然,它是高光指数// 光泽度的“泽”是点的概念,代表物体某个高光点的光泽程度o.Specular = _Shininess; // 越小光泽度越高,0为全白//o.Emission = tex.rgb;}ENDCG}Fallback "VertexLit"
}
相比较Phong模型,Blinn-phong模型只适用N•H替换了V•R,但却获得了明显的提高,它能提供比Phong更柔和、更平滑的高光,而且速度上也更快,因此成为很多CG软件中默认的光照渲染方法,同时也被集成到大多数的图形芯片中,而且在OpenGL和DirectX 3D的渲染管线中,它也是默认的光照模型。
由于这两个光照模型公式基本相同,所以只解释一下N•H:
N与前面相同,是顶点的单位法向量,而H则是入射光L和顶点到视点的单位向量的角平分线单位向量,通常也成为半角向量。其计算方法为:
H = (L + V) / (|L + V|)
Shader "Study/7_BlinnPhong" {Properties{_Color("Main Color", Color) = (1,1,1,1)_SpecColor("Specular Color", Color) = (0.5, 0.5, 0.5, 1)// 高光颜色_Shininess("Shininess", Range(0.01, 1)) = 0.078125// 高光指数【光泽度】_MainTex("Base (RGB) Gloss (A)", 2D) = "white" {}}SubShader{Tags{ "RenderType" = "Opaque" }LOD 300CGPROGRAM
#pragma surface surf BlinnPhongTest// 半角向量和BilnnPhong:使用入射光线和视线的中间平均值,即半角向量,然后使用该半角和法线计算出一个和视角相关的高光。// 相关参数:【lightDir点到光源单位向量】【viewDir点到摄像机单位向量】【atten衰减系数】【_LightColor0场景中平行光的颜色】float4 LightingBlinnPhongTest(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten){// 1.半角向量:求(点到光源+点到摄像机)的单位向量,他们的中间平均值float3 h = normalize(lightDir + viewDir);// 2.漫反射系数【点到光源单位向量与法线向量的余弦值】float diff = max(0, dot(s.Normal, lightDir));// 3.高光底数【半角向量与法线向量的余弦值】float nh = max(0, dot(s.Normal, h));// 4.高光系数:根据高光低数和高光指数求得float spec = pow(nh, s.Specular * 256) * s.Gloss;float4 c;// 5.最终光照rgb = 漫反射+半角高光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;}sampler2D _MainTex; // 主材质fixed4 _Color; // 主材质颜色half _Shininess; // 高光指数struct Input {float2 uv_MainTex; // 主材质的UV信息};void surf(Input IN, inout SurfaceOutput o) {// 取主纹理的对应当前像素点的值fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);// Albedo反照率,即物体反射光的数量与外来光数量的比值。// Albedo = 主纹理 x 主色调,反映了物体的基色,与任何光相关的信息(比如diffuse, shiness等)无关o.Albedo = tex.rgb * _Color.rgb; // 颜色纹理=主纹理*主材质颜色// Gloss光滑度[0, 1],用于控制反射的模糊程度,值越大,高光反射越清晰,反之则越模糊,0将无高光效果。// 光滑度的“滑”是面的概念,代表物体整体的光滑程度// 比如说,同样一块金属,在它生锈的过程中,其反射就会慢慢变弱,可以通过Gloss值控制// 实际上它是针对高光计算结果的附加系数o.Gloss = tex.a;o.Alpha = tex.a * _Color.a; // 透明度// Shininess光泽度[0, 1],又叫高光指数或镜面反射指数,注意,它在SurfaceOutput结构中的命名(Specular)很容易让人误解为它是高光强度,其实不然,它是高光指数// 光泽度的“泽”是点的概念,代表物体某个高光点的光泽程度o.Specular = _Shininess; // 越小光泽度越高,0为全白//o.Emission = tex.rgb;}ENDCG}Fallback "VertexLit"
}