高光反射部分计算公式为。
C specular=(Clight*Mspecular)*pow(max(0,dot(V,R)),Mgloss)
Clight是入射光的颜色和强度,材质的高光反射系数Mspecular,视角方向V和反射方向R点乘的结果再与高光系数pow。
R=2(dot(N,-L))N+L,幸运的是CG提供了计算发射方向的函数reflect。
下面是Shader代码
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Custom1/Specular" {
Properties{
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1)
_Gloss("Gloss",Range(8.0,256)) = 20
}
SubShader{
Tags { "LightMode" = "ForwardBase" }
LOD 200
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex :POSITION;
float3 normal:NORMAL;
};
struct v2f {
float4 pos:SV_POSITION;
fixed3 color : COLOR0;
};
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//计算漫反射
fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*max(0, dot(worldNormal, worldLightDir));
//计算反射方向
fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
//计算视角方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);
//高光反射计算公式
fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(dot(reflectDir, viewDir), _Gloss);
o.color = diffuse + ambient + specular;
return o;
}
fixed4 frag(v2f i) :SV_Target{
return fixed4(i.color,1.0);
}
ENDCG
}
}
FallBack "Specular"
}
图形学界大牛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更快速。
代码如下:
Shader "Custom1/Blinn-Phong"
{
Properties{
_Diffuse("Diffuse",Color) = (1,1,1,1)
_Specular("Specular",Color) = (1,1,1,1)
_Gloss("Gloss",Range(8.0,256)) = 20
}
SubShader{
Tags{ "LightMode" = "ForwardBase" }
LOD 200
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex :POSITION;
float3 normal:NORMAL;
};
struct v2f {
float4 pos:SV_POSITION;
fixed3 color : COLOR0;
};
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
//计算漫反射
fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*max(0, dot(worldNormal, worldLightDir));
//计算反射方向
//fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
//计算视角方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);
//计算半角
fixed3 halfDir = normalize(worldLightDir + viewDir);
//高光反射计算公式
fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(dot(worldNormal,halfDir), _Gloss);
o.color = diffuse + ambient + specular;
return o;
}
fixed4 frag(v2f i) :SV_Target{
return fixed4(i.color,1.0);
}
ENDCG
}
}
FallBack "Specular"
}