图形学界大牛Jim Blinn对Phong模型进行了改进,提出了Blinn-Phong模型。Blinn-Phong模型与Phong模型的区别是,把dot(V,R)换成了dot(N,H),其中H为半角向量,位于法线N和光线L的角平分线方向。Blinn-Phong模型可表示为:
Ispecular = Ks*Is* pow(( dot(N,H), n )
其中H = (L + V) / | L+V |,计算H比计算反射向量R更快速。
1) VertexShader
float4x4 matWorldViewProjection;
float4x4 matWorldView;
float4x4 matView;
float3 lightPos;
struct VS_INPUT
{
float4 position : POSITION0;
float3 normal: NORMAL;
};
struct VS_OUTPUT
{
float4 position : POSITION0;
float3 normalInView: TEXCOORD0;
float3 lightDirInView: TEXCOORD1;
float3 viewDirInView: TEXCOORD2;
};
VS_OUTPUT vs_main( VS_INPUT Input )
{
VS_OUTPUT Output;
Output.position = mul( Input.position, matWorldViewProjection );
Output.normalInView = mul( Input.normal, matWorldView);
Output.lightDirInView = lightPos - mul( Input.position, matWorldView);
float3 vPosition = mul( Input.position, matWorldView);
Output.viewDirInView = normalize(matView[3].xyz - vPosition);
return Output;
}
2) PixelShader
float4 ambientColor;
float4 diffuseColor;
float4 specularColor;
struct PS_INPUT
{
float3 normalInView: TEXCOORD0;
float3 lightDirInView: TEXCOORD1;
float3 viewDirInView: TEXCOORD2;
};
struct PS_OUTPUT
{
float4 color : COLOR0;
};
PS_OUTPUT ps_main( PS_INPUT In )
{
PS_OUTPUT Out;
In.normalInView = normalize(In.normalInView);
In.lightDirInView = normalize(In.lightDirInView);
float4 diffuse = max( 0, dot( In.normalInView, In.lightDirInView ));
diffuse = diffuse * diffuseColor;
float3 H = normalize(In.viewDirInView + In.lightDirInView);
float4 specular = specularColor * pow( max( 0, dot(H, In.normalInView)), 2 );
Out.color = ambientColor + diffuse + specular;
return Out;
}
Blinn-Phong光照效果