大家好,欢迎来到IT知识分享网。
图片和公式原理参考博客的链接
Phong和Blinn-Phong光照模型
Phong和Blinn-Phong是计算镜面反射光的两种光照模型,两者仅仅有很小的不同之处。
1.Phong模型
公式为:
在Phong光照模型中,关键是对发射向量的计算(如下图R向量)
上图中的位于表面“下面”的向量 ‘I’ 是原始 ‘I’ 向量的拷贝,并且二者是一样的,现在我们的目标计算出向量 ‘R’ 。根据向量相加原则,向量 ‘R’ 等于 ‘I’ + ‘V’,‘I’ 是已知的,所以我们需要做的就是找出向量 ‘V’。注意法向量 ‘N’ 的负方向就是 ‘-N’,我们可以在 ‘I’ 和 ‘-N’ 之间使用一个点乘运算就能得到 ‘I’ 在 ‘-N’ 上面的投影的模。这个模正好是 ‘V’ 的模的一半,由于 ‘V’ 与 ‘N’ 有相同的方向,我们可以将这个模乘上 ‘N’ (其模为 1 )再乘上 2 即可得到 ‘V’。总结一下就是下面的公式:
Unity中Shader代码如下:
Shader "Custom/Phong" { Properties { _LightDir("LightDir",Color) = (1,0,0) _LightColor("LightColor",Color) = (1,1,1) _Power("Power",Range(1,256)) = 1 _SpecularColor("SpecularColor",Color) = (1,1,1) _DiffuseColor("DiffuseColor",Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal:NORMAL; }; struct v2f { float4 vertex : SV_POSITION; float3 normal:NORMAL; float3 viewDir:TEXCOORD; }; float3 _LightColor; float3 _LightDir; float _Power; float3 _SpecularColor; float3 _DiffuseColor; v2f vert (appdata v) { v2f o; o.normal = UnityObjectToWorldNormal(v.normal); o.vertex = UnityObjectToClipPos(v.vertex); float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; o.viewDir = normalize(UnityWorldSpaceViewDir(worldPos)); return o; } fixed4 frag (v2f i) : SV_Target { //反射光方向 _LightDir = normalize(_LightDir); float3 ReflectLightDir = normalize(2 * dot(i.normal,_LightDir) * i.normal -_LightDir); //ReflectLightDir = reflect(-_LightDir,i.normal); half reflectiveFactor = max(0.0,dot(ReflectLightDir,i.viewDir)); half specularFactor =pow(reflectiveFactor,_Power); half diffuseFactor = max(0.0, dot(i.normal, _LightDir)); fixed3 diffuse = (diffuseFactor * _DiffuseColor + specularFactor * _SpecularColor) * _LightColor; return fixed4(diffuse,1); } ENDCG } } }
2.Blinn-Phong模型
Phong模型中计算反射光线的向量是一件相对比较耗时的任务,因此Blinn-Phong对这一点进行了改进。
Ks:物体对于反射光线的衰减系数
N:表面法向量
H:光入射方向L和视点方向V的中间向量
Shininess:高光系数
可见,通过该式计算镜面反射光是符合基本规律的,当视点方向和反射光线方向一致时,计算得到的H与N平行,dot(N,H)取得最大;当视点方向V偏离反射方向时,H也偏离N。
同时H的计算比起反射向量R的计算简单的多,R向量的计算需要若干次的向量乘法与加法,而H的计算仅仅需要一次加法。
Unity中Shader代码如下:
Shader "Custom/BlinnPhong" { Properties { _LightDir("LightDir",Color) = (1,0,0) _LightColor("LightColor",Color) = (1,1,1) _Power("Power",Range(1,256)) = 1 _SpecularColor("SpecularColor",Color) = (1,1,1) _DiffuseColor("DiffuseColor",Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal:NORMAL; }; struct v2f { float4 vertex : SV_POSITION; float3 normal:NORMAL; float3 viewDir:TEXCOORD; }; float3 _LightColor; float3 _LightDir; float _Power; float3 _SpecularColor; float3 _DiffuseColor; v2f vert (appdata v) { v2f o; o.normal = UnityObjectToWorldNormal(v.normal); o.vertex = UnityObjectToClipPos(v.vertex); float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; o.viewDir = normalize(UnityWorldSpaceViewDir(worldPos)); return o; } fixed4 frag (v2f i) : SV_Target { //反射光方向 _LightDir = normalize(_LightDir); half3 h = normalize (_LightDir + i.viewDir); fixed diffFactor = max (0, dot (i.normal, _LightDir)); float nh = max (0, dot (i.normal, h)); float specularFactor = pow (nh, _Power); fixed3 diffuse = (diffFactor * _DiffuseColor + specularFactor * _SpecularColor) * _LightColor; return fixed4(diffuse,1); } ENDCG } } }
Phong和BlinnPhong在_Power值为16时候的对比图如下:
(左侧为BlinnPhong右侧为Phong)
3.用途区别
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/147575.html