白泽图

  • 文章
    • Unity渲染
    • Unity项目开发
    • 工具
    • 数学
    • 算法
    • 网站搭建
    • 网络&操作系统
蒋程个人博客
互联网技术经验总结&分享
  1. 首页
  2. Unity渲染
  3. 正文

Phong光照模型与BlinnPhong光照模型

2020-12-07 2395点热度 0人点赞 0条评论

现实中光照是一件非常复杂的事情,人眼能看到的某个物体是因为该物体反射了光进入了人的眼晴,而物体反射光的来源并不单单只来源于光源,也包含其他物体反射出来的光,也就是说光线是在物体之间反复弹射(举个例子:光滑的瓷砖表面会折射出其他物体),除此之外,光滑的物体还会使人眼接收到更亮高光效果,所以说想要达到更加逼真的光照效果单靠Lambert光照模型模拟的漫反射效果是远远不够的。

原理参考资料: 现代计算机图形学入门-闫令琪 第8讲 (说明图片来源该课件截图)

Phong光照模型

\(L=L_{a}+L_{d}+L_{s}\)

即:  光照最终结果=环境光照+漫反射光照+镜面反射光照

1.环境光

由于\(L_{a}\)过于复杂(涉及到光照追踪),在该模型中被直接简化成\(L_{a}=k_{a}I_{a}\),即一个光照强度乘以一个常量,目的只有一个,让一个没有受到光源照射的物体不会那么黑(有个默认颜色),这里可以参考之前Lambert光照模型里面的图片效果

这里解释一下,但凡我们能看到的物体都一定反射了光,哪怕它没有直接接受光源的光,它也会反射来自其他地方的光,就是上面所说的接收了其他物体反射出来的光

2.漫反射

直接参考前文所讲的Lambert光照模型

3.镜面反射(核心点)

如图紫色方块代表单位受光面积(受光点),向量L为光入射方向,向量R为反射方向,向量V为观察方向,观察上面可以发现,当向量R与向量V接近时(夹角趋向0),人眼会受到高光效果。所以可以得出以下公式

\(L_{s}=k_{s}(I/r^{2})\max(0,\vec{R}\cdot\vec{V})^{p}\)

(衰减与系数参考Lamert光照模型)

指数系数p的作用:


在现实生活中,高光一般只存在于光的反射方向与观察方向夹角趋于0时才会有,稍微偏一点角度都不会看到高光效果,上图展示了不同指数的变化曲线,可以发现当指数越大,曲线变化越剧烈,所以公式中的指数系数p,就是用来处理这个现象的

BlinnPhong光照模型

BlinnPhong光照模型是Phong的改进型,Phong模型中向量R的计算非常的耗时(光照是逐片元计算的)

通过上图观察,向量V与量向R之间的夹角可以转换成向量H与法线向量N的夹角

而\(\vec{H}=\vec{L}+\vec{V}\) (计算量直接变成两个相量相加)

所以Phong模型的公式可以优化成:

\(L_{s}=k_{s}(I/r^{2})\max(0,\vec{N}\cdot (\vec{L}+\vec{V}))^{p}\)

最后完整公式:

\(L=L_{a}+L_{d}+L_{s}\)

    \(=k_{a}I_{a}+k_{d}(I/r^{2})\max(0,\vec{N}\cdot\vec{L})+k_{s}(I/r^{2})\max(0,\vec{N}\cdot (\vec{L}+\vec{V}))^{p}\)

UnityShader 实现代码如下:

Shader "Custom/BlinnPhongLight"
{
	Properties
	{
		_MainTex("MainTex",2D) = "white"{}
		_Gloss("Gloss",Range(8.0,256)) = 20
	}
	SubShader
	{
		LOD 100
		Pass
		{
			Name "LambertLight"
			Tags{"LightMode" = "ForwardAdd"}
			CGPROGRAM
			#pragma vertex vert 
			#pragma fragment frag

			uniform float4 _LightColor0;
			struct a2v
			{
				float4 model_vertex : POSITION;
				float3 model_normal : NORMAL;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float4 clip_pos : SV_POSITION;
				float2 uv : TEXCOORD0;
				float3 world_pos : TEXCOORD1;
				float3 world_normal : TEXCOORD2;
				float4 objPos : TEXCOORD3;
			};

			sampler2D _MainTex;
			fixed _Gloss;

			v2f vert(a2v v)
			{
				v2f o;
				o.uv = v.uv;
				o.clip_pos = UnityObjectToClipPos(v.model_vertex);
				o.world_normal = mul((float3x3)unity_ObjectToWorld, v.model_normal);  //UnityObjectToWorldNormal(v.model_normal);
				o.world_pos = mul(unity_ObjectToWorld, v.model_vertex).xyz;
				o.objPos = v.model_vertex;
				return o;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				//顶点法线(世界空间)
				fixed3 world_normal = normalize(i.world_normal);
				//光入射方向(世界空间)
				fixed3 world_light = _WorldSpaceLightPos0.xyz - i.world_pos.xyz;
				fixed3 world_light_dir = normalize(world_light);
				//观察方向
				fixed3 world_view_dir = normalize(_WorldSpaceCameraPos.xyz - i.world_pos.xyz);
				//距离光源的位置
				float world_light_distance = length(world_light);
				//衰減系数
				float atten = 1 / pow(world_light_distance, 2);
				//环境光(固定系数)
				fixed3 ambientColor = UNITY_LIGHTMODEL_AMBIENT.rgb;
				//漫反射
				fixed3 diffuseColor = atten * _LightColor0.rgb * max(0, dot(world_normal, world_light_dir));
				//镜面反射
				fixed3 specularColor = atten * _LightColor0.rgb * pow(max(0, dot(world_normal, normalize(world_view_dir + world_light_dir)) ), _Gloss);
				//最终光颜色
				fixed3 lightColor = ambientColor + diffuseColor +specularColor;
				//贴图颜色
				fixed4 texture_color = tex2D(_MainTex, i.uv);
				//叠加光颜色
				fixed3 finalColor = texture_color.rgb * lightColor;
				return fixed4(finalColor, 1.0);
			}
			ENDCG
		}
	}
}


最终效果如下:

标签: 暂无
最后更新:2020-12-07

蒋程

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

COPYRIGHT © 2023 白泽图. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

登录
注册|忘记密码?