Half Lambert 模型(也叫作半兰伯特模型)在 Lambert 模型的基础之上做了一些优化。
在 Lambert 模型中,光照无法到达的区域,比如模型的背面,模型外观通常是全黑的,没有任何明暗变化,而 Half Lambert 模型就是改善这一状况。
回顾 Lambert 模型的计算公式如下:
$c_{diffuse} = (c_{light} \cdot m_{diffuse}) \cdot max (0,n \cdot I)$
当光源和法向量夹角的余弦值为负数的时候,所得到的结果始终都是 0 了,所以就会有图中看到的一片黑。
Half Labmert 模型的计算公式如下:
$c_{diffuse} = (c_{light} \cdot m_{diffuse}) \cdot ( a (n \cdot I) + b)$
同样会计算余弦值,但是会把余弦值先缩放 a 倍,再偏移 b 大小,不再用 max 函数避免为负值。
绝大多数情况下,a 和 b 的值都是 0.5,所以也是为什么叫 half 了。
$c_{diffuse} = (c_{light} \cdot m_{diffuse}) \cdot ( 0.5 (n \cdot I) + 0.5)$
余弦值的取值范围是 [-1,1] ,经过缩放和偏移后就是 [0,1] 了,这样一来原本余弦值为负数导致直接取 0 的点,变成了取值结果在 [0,0.5] 了,从而就可以体现出明暗变化,不同的点积结果会映射到不同的值上。
对于 unity shader 的计算,也不会有太大的改变,主要如下:
1fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
2fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
3fixed halfLambert = dot(worldNormal,worldLight) * 0.5 + 0.5;
原本用 saturate 函数对点积结果做取值范围约束,现在直接通过映射来保证范围了。
具体的 shader 代码如下,以逐顶点着色为例:
1Shader "Custom/HalfLambertShader"
2{
3 Properties
4 {
5 _Diffuse ("Diffuse",Color) = (1,1,1,1)
6 }
7 SubShader
8 {
9
10 Pass
11 {
12 Tags{ "LightMode" = "ForwardBase"}
13 CGPROGRAM
14 #pragma vertex vert
15 #pragma fragment frag
16 #include "UnityCG.cginc"
17 #include "Lighting.cginc"
18 fixed4 _Diffuse;
19 struct appdata
20 {
21 float4 vertex : POSITION;
22 float3 normal : NORMAL;
23 };
24 struct v2f
25 {
26 float4 pos : SV_POSITION;
27 fixed3 color : COLOR;
28 };
29 v2f vert (appdata v)
30 {
31 v2f o;
32 o.pos = UnityObjectToClipPos(v.vertex);
33
34 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
35 fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
36 fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
37
38 fixed halfLambert = dot(worldNormal,worldLight) * 0.5 + 0.5;
39 fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;
40 o.color = ambient + diffuse;
41 return o;
42 }
43 fixed4 frag (v2f i) : SV_Target
44 {
45 return fixed4(i.color,1.0);
46 }
47 ENDCG
48 }
49 }
50}
渲染效果如下:
可以看到 Half Lambert 模型在背面有了明显的亮暗变化。
同时 Half Lambert 模型在正面也会更加明亮一点。
小结
Half Lambert 模型在 Lambert 基础之上做了优化,而这正是应了图像渲染里面的那就话:如果看起来是对的,那么它就是对的。
原创文章,转载请注明来源: Unity Shader 光照基础之 Half Lambert 光照模型
相关文章
- Unity Shader 光照基础之Lambert光照模型
- Unity Shader 光照基础内容
- Unity Shader 显示一张图片纹理
- UnityShader 的基本概念
- Unity 物体的基本操作
留言