Phong和Blinn-Phong是計算鏡面反射光的兩種光照模型,二者僅僅有很小的不一樣之處。算法
1.Phong模型spa
Phone模型計算中的一個關鍵步驟就是反射向量R的計算:3d
上圖中的位於表面「下面」的向量 ‘I’ 是原始 ‘I’ 向量的拷貝,而且兩者是同樣的,如今咱們的目標計算出向量 ‘R’ 。根據向量相加原則,向量 ‘R’ 等於 'I' + 'V',‘I’ 是已知的,因此咱們須要作的就是找出向量 ‘V’。注意法向量 ‘N’ 的負方向就是 ‘-N’,咱們能夠在 ‘I’ 和 ‘-N’ 之間使用一個點乘運算就能獲得 ‘I’ 在 ‘-N’ 上面的投影的模。這個模正好是 ‘V’ 的模的一半,因爲 ‘V’ 與 ‘N’ 有相同的方向,咱們能夠將這個模乘上 ‘N’ (其模爲 1 )再乘上 2 便可獲得 ‘V’。總結一下就是下面的公式:code
2.Blinn-Phong模型orm
Phong模型中計算反射光線的向量是一件相對比較耗時的任務,所以Blinn-Phong對這一點進行了改進。blog
Ks:物體對於反射光線的衰減係數it
N:表面法向量io
H:光入射方向L和視點方向V的中間向量form
Shininess:高光係數class
可見,經過該式計算鏡面反射光是符合基本規律的,當視點方向和反射光線方向一致時,計算獲得的H與N平行,dot(N,H)取得最大;當視點方向V偏離反射方向時,H也偏離N。
同時H的計算比起反射向量R的計算簡單的多,R向量的計算須要若干次的向量乘法與加法,而H的計算僅僅須要一次加法。
下面是用cg着色語言書寫的Phong和Blinn-Phong的頂點和片斷着色程序
Phong_FragmentLighting_v.cg
1 struct V2F{ 2 float4 position:POSITION; 3 float3 worldPosition: TEXCOORD0; 4 float3 worldNormal :TEXCOORD1; 5 }; 6 void Phong_FragmentLighting_v(float4 position :POSITION, 7 float4 normal:NORMAL, 8 uniform float4x4 modelMatrix, 9 uniform float4x4 modelMatrix_IT, 10 uniform float4x4 modelViewProj, 11 out V2F O){ 12 O.position=mul(modelViewProj,position); 13 O.worldPosition=mul(modelMatrix,position).xyz; 14 O.worldNormal=normalize(mul(modelMatrix_IT,normal)).xyz; 15 }
Phong_FragmentLighting_f.cg
1 void Phong_FragmentLighting_f(float3 position :TEXCOORD0, 2 float3 normal: TEXCOORD1, 3 uniform float3 globalAmbient, 4 uniform float3 lightColor, 5 uniform float3 lightPosition, 6 uniform float3 eyePosition, 7 uniform float3 Ke, 8 uniform float3 Ka, 9 uniform float3 Kd, 10 uniform float3 Ks, 11 uniform float shininess, 12 out float4 color:COLOR) 13 { 14 float3 N=normalize(normal); 15 float3 L=normalize(lightPosition-position); 16 float3 V=normalize(eyePosition-position); 17 18 float3 R=reflect(-L,N); 19 R=normalize(R); 20 21 // Compute emissive term 22 float3 emissive = Ke; 23 24 // Compute ambient term 25 float3 ambient = Ka * globalAmbient; 26 27 // Compute the diffuse term 28 float diffuseLight = max(dot(N, L), 0); 29 float3 diffuse = Kd * lightColor * diffuseLight; 30 31 // Compute the specular term 32 float specularLight = pow(max(dot(V, R), 0), shininess); 33 if (diffuseLight <= 0) specularLight = 0; 34 float3 specular = Ks * lightColor * specularLight; 35 36 //color.xyz = emissive + ambient + diffuse + specular; 37 color.xyz=ambient + diffuse + specular; 38 color.w = 1; 39 }
BlinnPhong_FragmentLighting_v.cg
1 struct V2F{ 2 float4 position:POSITION; 3 float3 worldPosition: TEXCOORD0; 4 float3 worldNormal :TEXCOORD1; 5 }; 6 void BlinnPhong_FragmentLighting_v(float4 position :POSITION, 7 float4 normal:NORMAL, 8 uniform float4x4 modelMatrix, 9 uniform float4x4 modelMatrix_IT, 10 uniform float4x4 modelViewProj, 11 out V2F O){ 12 O.position=mul(modelViewProj,position); 13 O.worldPosition=mul(modelMatrix,position).xyz; 14 O.worldNormal=normalize(mul(modelMatrix_IT,normal)).xyz; 15 }
BlinnPhong_FragmentLighting_f.cg
1 void BlinnPhong_FragmentLighting_f(float3 position :TEXCOORD0, 2 float3 normal: TEXCOORD1, 3 uniform float3 globalAmbient, 4 uniform float3 lightColor, 5 uniform float3 lightPosition, 6 uniform float3 eyePosition, 7 uniform float3 Ke, 8 uniform float3 Ka, 9 uniform float3 Kd, 10 uniform float3 Ks, 11 uniform float shininess, 12 out float4 color:COLOR) 13 { 14 float3 N=normalize(normal); 15 float3 L=normalize(lightPosition-position); 16 float3 V=normalize(eyePosition-position); 17 18 float3 H=normalize(L+V); 19 20 // Compute emissive term 21 float3 emissive = Ke; 22 23 // Compute ambient term 24 float3 ambient = Ka * globalAmbient; 25 26 // Compute the diffuse term 27 float diffuseLight = max(dot(N, L), 0); 28 float3 diffuse = Kd * lightColor * diffuseLight; 29 30 // Compute the specular term 31 float specularLight = pow(max(dot(H, N), 0), shininess); 32 if (diffuseLight <= 0) specularLight = 0; 33 float3 specular = Ks * lightColor * specularLight; 34 35 color.xyz=ambient + diffuse + specular; 36 color.w = 1; 37 }
效果對比:
Phong光照模型
Blinn-Phong光照模型經過簡單的對比發現,在相同條件下Blinn-Phong的高光範圍要比Phong更大,寫實效果Phong光照模型更好。但算法簡單,運行速度快是Blinn-Phong光照模型的優勢。