Shader基本光照模型——半兰伯特模型

Shader "zxwlx/HalfLambert"
{
	Properties{
		_Diffuse("Diffuse", Color) = (1,1,1,1)
	}
	SubShader
	{
		Pass
		{
			Tags{ "RenderType" = "Opaque" }
 
			CGPROGRAM

			#include "Lighting.cginc"

			#pragma vertex vert
			#pragma fragment frag	

			fixed4 _Diffuse;

			struct a2v
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			struct v2f
			{
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
			};
			v2f vert(a2v v)
			{
				v2f o;
				//把顶点坐标从模型空间转换到世界空间
				o.pos = UnityObjectToClipPos(v.vertex);
				//把法线转化到世界空间
				o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
				return o;
			}
			fixed4 frag(v2f i) : SV_Target
			{
				//归一化法线,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出的
				fixed3 worldNormal = normalize(i.worldNormal);
				//把光照方向归一化
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
				//半兰伯特光照,将原来(-1,1)区间的光照条件转化到了(0,1)区间,既保证了结果的正确,又整体提升了亮度,保证非受光面也能有光,而不是全黑
				fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;
				//最终输出颜色为lambert光强*材质diffuse颜色*光颜色
				fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz;
				return fixed4(diffuse, 1.0);
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

原理公式:漫反射光的光强仅与入射光的方向和反射点处表面法向夹角的余弦成正比。

diffuse = I*cosθ;

diffuse:反射光线的的光强;

I:入射光线的光强,方向如上图所示;

cosθ:入射光线和该顶点法线的余弦,如上图所示;cosθ = L*N;

所以,最后的数学表达式为:diffuse = I*(L*N);

猜你喜欢

转载自blog.csdn.net/qq_43461641/article/details/89646531