概述
Blinn-Phong式高光反射模型是对Phong式高光反射模型的改进,它不再使用反射向量计算镜面反射,而是使用半角向量进行计算。
半角向量为视角方向和灯光方向的角平分线方向。
高光反射光照颜色 = 光源的颜色 * 材质高光反射颜色 * max(0, dot(标准化后顶点法线方向向量, 标准化后半角方向向量))幂
幂 代表光泽度
Blinn-Phong和Phong的区别
- 高光散射:Blinn-Phong模型的高光通常会产生相对均匀的高光散射,这会使物体看起来光滑均匀。Phong模型的高光可能会呈现更为锐利的高光散射,导致一些区域看起来特别亮,而另一些区域特别暗。
- 高光锐度:Blinn-Phong模型的高光通常具有较广的散射角,因此看起来不那么锐利。Phong模型的高光可能会更加锐利,特别是在观察者和光源夹角较小时,可能表现为小而亮的点。
- 光滑度和表面纹理:Blinn-Phong模型通常更适合表现光滑的表面,因为它考虑了表面微观凹凸之间的相互作用,使得光照在表面上更加均匀分布。Phong模型更适合表现具有粗糙表面物体的物体,因为它的高光散射可能会使纹理和细节更加突出。
- 镜面高光大小:Blinn-Phong模型通常产生的镜面高光相对较大,但均匀分布。Phong模型可能会产生较小且锐利的高光。
- 性能上的不同:Blinn-Phong模型通常比Phong模型计算更快。
ShaderLab示例
Blinn-Phong式高光反射模型逐顶点光照
SubShader
{
Pass
{
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _SpecularColor;
float _SpecularLevel;
struct v2f
{
float4 vertex : SV_POSITION;
fixed3 color : COLOR;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
// 获得标准化顶点法线向量
float3 normal = UnityObjectToWorldDir(v.normal);
// 将模型空间下的顶点位置转换到世界空间下
float3 worldPos = mul(UNITY_MATRIX_M, v.vertex);
// 获取标准化半角方向向量
float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - worldPos);
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
float3 halfAngle = normalize(viewDir + lightDir);
o.color = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(normal, halfAngle)), _SpecularLevel);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return fixed4(i.color.rgb, 1);
}
ENDCG
}
}
Blinn-Phong式高光反射模型逐片元光照
SubShader
{
Tags
{
"LightMode"="ForwardBase"
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
fixed4 _SpecularColor;
float _SpecularLevel;
struct v2f
{
float4 vertex : SV_POSITION;
// 世界空间下的法线信息
fixed3 wNormal : NORMAL;
// 世界空间下的顶点坐标
float3 wPos : TEXCOORD0;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.wNormal = UnityObjectToWorldNormal(v.normal);
o.wPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
// 获取标准化观察方向向量
float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.wPos);
// 获取标准化半角方向向量
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
float3 halfAngle = normalize(viewDir + lightDir);
return fixed4(_LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(i.wNormal, halfAngle)), _SpecularLevel), 1);
}
ENDCG
}
}