7.Phong 和 BlinnPhong

Lambert漫反射光照模型,这是一个用来模拟粗糙表面对光线的漫反射现象的经验模型,对于纸张、粗糙墙壁等等来说,这个模型或许够用,但对于金属这样的光滑表面来说,我们就需要使用Phong模型来模拟光滑表面对光线的镜面反射现象。同Lambert一样,这个模型也是经验模型,而且在程序中,我们经常同时使用Lambert和Phong两个模型,因为在现实世界中,任何表面都会同时发生漫反射和镜面反射两种现象,因此我们就要使用两种模型分别计算两种反射后的光强(也就是顶点颜色值),是渲染的效果看起来真实一些。但要注意,这样做并不会带来真正真实的渲染效果,毕竟这两种模型都是经验模型,考虑的都是理想情况下。而Blinn-phong光照模型是基于Phong的修正模型。

设顶点的单位法向量为N,有公式:

R + L = (2N • L)N   (这里再次提醒一下,L的方向是由顶点指向光源的)

由这个可以推出:

R = (2N • L)N - L

因此Phong的公式如下图左图所示。


imageimage

Shader "Study/7_Phong" {
	Properties{
		_Color("Main Color", Color) = (1,1,1,1)
		_SpecColor("Specular Color", Color) = (0.5, 0.5, 0.5, 1)// 高光颜色
		_Shininess("Shininess", Range(0.01, 1)) = 0.078125// 高光指数【光泽度】
		_MainTex("Base (RGB) Gloss (A)", 2D) = "white" {}
	}
		SubShader{
		Tags{ "RenderType" = "Opaque" }
		LOD 300

		CGPROGRAM
#pragma surface surf BlinnPhongTest
		// 半角向量和BilnnPhong:使用入射光线和视线的中间平均值,即半角向量,然后使用该半角和法线计算出一个和视角相关的高光。
		// 相关参数:【lightDir点到光源单位向量】【viewDir点到摄像机单位向量】【atten衰减系数】【_LightColor0场景中平行光的颜色】
		float4 LightingBlinnPhongTest(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten)
	{
		// 1.半角向量:求(点到光源+点到摄像机)的单位向量,他们的中间平均值
		float3 h = normalize(lightDir + viewDir);
		// 2.漫反射系数【点到光源单位向量与法线向量的余弦值】
		float diff = max(0, dot(s.Normal, lightDir));
		// 3.反射向量
		float3 r = 2 * dot(s.Normal, lightDir) * s.Normal - lightDir;
		// 4.高光底数【反射向量与视角向量的余弦值】
		float re = max(0, dot(r, viewDir));
		// 5.高光系数:根据高光低数和高光指数求得
		float spec = pow(re, s.Specular * 256) * s.Gloss;
		float4 c;
		// 6.最终光照rgb = 漫反射+半角高光
		c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2);
		c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten;
		return c;
	}
	sampler2D _MainTex; // 主材质
	fixed4 _Color;  // 主材质颜色
	half _Shininess; // 高光指数
	struct Input {
		float2 uv_MainTex; // 主材质的UV信息
	};
	void surf(Input IN, inout SurfaceOutput o) {
		// 取主纹理的对应当前像素点的值
		fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);

		// Albedo反照率,即物体反射光的数量与外来光数量的比值。
		// Albedo = 主纹理 x 主色调,反映了物体的基色,与任何光相关的信息(比如diffuse, shiness等)无关
		o.Albedo = tex.rgb * _Color.rgb;    // 颜色纹理=主纹理*主材质颜色

											// Gloss光滑度[0, 1],用于控制反射的模糊程度,值越大,高光反射越清晰,反之则越模糊,0将无高光效果。
											// 光滑度的“滑”是面的概念,代表物体整体的光滑程度
											// 比如说,同样一块金属,在它生锈的过程中,其反射就会慢慢变弱,可以通过Gloss值控制
											// 实际上它是针对高光计算结果的附加系数
		o.Gloss = tex.a;
		o.Alpha = tex.a * _Color.a;      // 透明度
										 // Shininess光泽度[0, 1],又叫高光指数或镜面反射指数,注意,它在SurfaceOutput结构中的命名(Specular)很容易让人误解为它是高光强度,其实不然,它是高光指数
										 // 光泽度的“泽”是点的概念,代表物体某个高光点的光泽程度
		o.Specular = _Shininess; // 越小光泽度越高,0为全白
								 //o.Emission = tex.rgb;
	}
	ENDCG
	}
		Fallback "VertexLit"
}


相比较Phong模型,Blinn-phong模型只适用N•H替换了V•R,但却获得了明显的提高,它能提供比Phong更柔和、更平滑的高光,而且速度上也更快,因此成为很多CG软件中默认的光照渲染方法,同时也被集成到大多数的图形芯片中,而且在OpenGL和DirectX 3D的渲染管线中,它也是默认的光照模型。

 

由于这两个光照模型公式基本相同,所以只解释一下N•H:

N与前面相同,是顶点的单位法向量,而H则是入射光L和顶点到视点的单位向量的角平分线单位向量,通常也成为半角向量。其计算方法为:

H = (L + V) / (|L + V|)

Shader "Study/7_BlinnPhong" {
	Properties{
		_Color("Main Color", Color) = (1,1,1,1)
		_SpecColor("Specular Color", Color) = (0.5, 0.5, 0.5, 1)// 高光颜色
		_Shininess("Shininess", Range(0.01, 1)) = 0.078125// 高光指数【光泽度】
		_MainTex("Base (RGB) Gloss (A)", 2D) = "white" {}
	}
		SubShader{
		Tags{ "RenderType" = "Opaque" }
		LOD 300

		CGPROGRAM
#pragma surface surf BlinnPhongTest
		// 半角向量和BilnnPhong:使用入射光线和视线的中间平均值,即半角向量,然后使用该半角和法线计算出一个和视角相关的高光。
		// 相关参数:【lightDir点到光源单位向量】【viewDir点到摄像机单位向量】【atten衰减系数】【_LightColor0场景中平行光的颜色】
		float4 LightingBlinnPhongTest(SurfaceOutput s, float3 lightDir, float3 viewDir, float atten)
	{
		// 1.半角向量:求(点到光源+点到摄像机)的单位向量,他们的中间平均值
		float3 h = normalize(lightDir + viewDir);
		// 2.漫反射系数【点到光源单位向量与法线向量的余弦值】
		float diff = max(0, dot(s.Normal, lightDir));
		// 3.高光底数【半角向量与法线向量的余弦值】
		float nh = max(0, dot(s.Normal, h));
		// 4.高光系数:根据高光低数和高光指数求得
		float spec = pow(nh, s.Specular * 256) * s.Gloss;
		float4 c;
		// 5.最终光照rgb = 漫反射+半角高光
		c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2);
		c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten;
		return c;
	}
	sampler2D _MainTex; // 主材质
	fixed4 _Color;  // 主材质颜色
	half _Shininess; // 高光指数
	struct Input {
		float2 uv_MainTex; // 主材质的UV信息
	};
	void surf(Input IN, inout SurfaceOutput o) {
		// 取主纹理的对应当前像素点的值
		fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);

		// Albedo反照率,即物体反射光的数量与外来光数量的比值。
		// Albedo = 主纹理 x 主色调,反映了物体的基色,与任何光相关的信息(比如diffuse, shiness等)无关
		o.Albedo = tex.rgb * _Color.rgb;    // 颜色纹理=主纹理*主材质颜色

											// Gloss光滑度[0, 1],用于控制反射的模糊程度,值越大,高光反射越清晰,反之则越模糊,0将无高光效果。
											// 光滑度的“滑”是面的概念,代表物体整体的光滑程度
											// 比如说,同样一块金属,在它生锈的过程中,其反射就会慢慢变弱,可以通过Gloss值控制
											// 实际上它是针对高光计算结果的附加系数
		o.Gloss = tex.a;
		o.Alpha = tex.a * _Color.a;      // 透明度
										 // Shininess光泽度[0, 1],又叫高光指数或镜面反射指数,注意,它在SurfaceOutput结构中的命名(Specular)很容易让人误解为它是高光强度,其实不然,它是高光指数
										 // 光泽度的“泽”是点的概念,代表物体某个高光点的光泽程度
		o.Specular = _Shininess; // 越小光泽度越高,0为全白
								 //o.Emission = tex.rgb;
	}
	ENDCG
	}
		Fallback "VertexLit"
}


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值