TA之路——Shader学习05(光照模型之高光反射(BlinnPhong))

写在前面:
高光反射一般建立在已有漫反射的基础上对模型进行颜色的叠加渲染。在这里我们多个一个对象——视野方向。
高光反射的计算包含平行光方向、视野方向、反射光方向等元素。
逐顶点:

Shader "MyShader/Specular_Vertex"{
	ProPerties{
	_Diffuse("Diffuse Color",Color)=(1,1,1,1)
	_Gloss("Specular Gloss",Range(1,20))=20
	_Specular("Specular Color",Color)=(1,1,1,1)
	}
	SubShader{
		Pass{
			Tags{"LightMode"="ForwardBase"};
			CGPROGRAM
			#include "Lighting.cginc"
			#pragma Vertex vert
			#pragma Fragment frag
			fixed4 _Diffuse;
			half _Gloss;
			fixed4 _Specular;
			struct a2v{
				float4 ps:POSITION;
				fixed3 nm:NORMAL;
			};
			struct v2f{
				float4 position:SV_POSITION;
				fixed3 cl:COLOR;
			};
			v2f vert(a2v v){
				v2f f;
				f.position=mul(v.ps,UNITY_MATRIX_MVP);
				fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
				fixed3 normalDir=normalize(mul(v.nm,(float3x3)_World2Object));
				fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);
				fixed3 halfLambert=dot(lightDir,normalDir)*.5+0.5;
				fixed3 Diffuse=_LightColor0*halfLambert*_Diffuse;
				//高光反射计算
				fixed3 reflectDir=normalize(reflect(-lightDir,normalDir));//反射光方向
				fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-mul(v.ps,_World2Object);//视野方向=摄像机坐标-顶点坐标
				fixed3 Specular=_LightColor*pow(max(dot(reflectDir,viewDir),0),_Gloss)*_Specular;//Specular=直射光颜色*pow(max(视野方向和反射光方向之间的点积,0),光泽度)*高光颜色
				f.cl=Diffuse+ambient+Specular;
				return f;
			}
			fixed4 frag(v2f f):SV_Target{
				return fixed4(f.cl,1);
			}
			
			ENDCG
		}
	}

Fallback "VertexLit"
}

当然,一般情况下我们都常用的是BlinnPhong光照模型,以上部分代码稍作修改:

			fixed3 reflectDir=normalize(reflect(-lightDir,normalDir));//反射光方向
			fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-mul(v.ps,(float3x3)_World2Object);//视野方向=摄像机坐标-顶点坐标
			fixed3 Specular=_LightColor*pow(max(dot(reflectDir,viewDir),0),_Gloss)*_Specular;//Specular=直射光颜色*pow(max(视野方向和反射光方向之间的点积,0),光泽度)*高光颜色

修改为:

			fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-mul(v.ps,(float3x3)_World2Object);//视野方向=摄像机坐标-顶点坐标
			fixed3 halfBlinn=normalize(lightDir+viewDir);//将平行光和视野方向的平分线单位化
			fixed3 Specular=_LightColor*pow(max(dot(normalDir,halfBlinn),0),_Gloss)*_Specular;//BlinnPhong计算公式:高光反射=直射光颜色*pow(max(法线和平行光与视野方向的平分线的点积,0),光泽度)*高光颜色

逐像素:

Shader "MyShader/Specular_Fragment"{
	Properties{
		_Diffuse("Diffuse Color",Color)=(1,1,1,1)
		_Gloss("Specular Gloss",Range(1,20))=20
		_Specular("Specular Color",Color)=(1,1,1,1)
	}
	SubShader{
		Pass{
			Tags{"LightMode"="ForwardBase"};
			CGPROGRAM
			#include "Lighting.cginc"
			#pragma Vertex vert
			#pragma Fragment frag
			fixed4 _Diffuse;
			half _Gloss;
			fixed4 _Specular;
			struct a2v{
				float4 ps:POSITION;
				fixed3 nm:NORMAL;
			};
			struct v2f{
				float4 position:SV_POSITION;
				float3 vertexV:TEXCROOD0;
				float3 normalV:TEXCROOD1;
			};
			v2f vert(a2v v){
				v2f f;
				f.position=mul(v.ps,UNITY_MATRIX_MVP);
				f.worldNormal=mul(v.nm,(float3x3)unity_WorldToObject);//世界空间下的法线方向
				f.worldVertex=mul(v.ps,unity_WorldToObject);//世界空间下的顶点坐标
				return f;
			}
			fixed4 frag(v2f f):SV_Target{
				fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
				fixed3 normalDir=normalize(f.worldNormal);
				fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);
				fixed3 halfLambert=dot(lightDir,normalDir)*.5+0.5;
				fixed3 Diffuse=_LightColor0*halfLambert*_Diffuse;
				//高光反射计算
				fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-f.worldVertex);//视野方向=摄像机坐标-顶点坐标
				fixed3 halfBlinn=normalize(lightDir+viewDir);//将平行光和视野方向的平分线单位化
				fixed3 Specular=_LightColor*pow(max(dot(normalDir,halfBlinn),0),_Gloss)*_Specular;//BlinnPhong计算公式:高光反射=直射光颜色*pow(max(法线和平行光与视野方向的平分线的点积,0),光泽度)*高光颜色
				fixed3 tempColor=Diffuse+ambient+Specular;
				return fixed4(tempColor,1);
			}
			ENDCG
		}	
	}	
	Fallback "VertexLit"
}

逐顶点光照和逐像素光照渲染出来的效果对比:
在这里插入图片描述
使用BlinnPhong和不使用的对比:
在这里插入图片描述
UnityCG.cginc中一些常用的函数:
摄像机方向:
float3 WorldSpaceViewDir(float4 v) 根据模型空间下的顶点坐标得到从这个点到摄像机的观察方向
float3 UnityWorldSpaceViewDir(float4 v) 把世界空间下的顶点坐标转换成从这个点到摄像机的观察方向
float3 ObjSpaceViewDir(float4 v) 把模型空间中的顶点坐标转换成模型空间中从这个点到摄像机的观察方向
//光源方向:
float3 WorldSpaceLightDir(float4 v) 根据模型空间中的顶点坐标得到从这个点到光源的方向
float3 UnityWorldSpaceLightDir(float4 v) 把世界空间下的顶点坐标转换成从这个点到光源的方向
float3 ObjSpaceLightDir(float4 v) 把模型空间中的顶点坐标转换成模型空间中从这个点到光源的方向
//方向转换
float3 UnityObjectToWorldNormal(float3 nom) 把法线方向从模型空间转换到世界空间
float3 UnityObjectToWorldDir(float3 dir)把方向从模型空间转换到世界空间
float3 UnityWorldToObjectDir(float3 dir)把方向从世界空间转换到模型空间

示例:
以上代码中

f.worldNormal=mul(v.nm,(float3x3)unity_WorldToObject);
fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);
fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-f.worldVertex);

这几行代码可可写作

f.worldNormal=UnityObjectToWorldNormal(v.nm);
fixed3 lightDir=normalize(UnityWorldSpaceLightDir(f.worldVertex).xyz);
fixed3 viewDir=normalize(UnityWorldSpaceViewDir(f.worldVertex).xyz);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值