US3S1L3-1——半兰伯特光照模型的逐顶点光照

利用半兰伯特光照模型实现光照效果(逐顶点光照)

半兰伯特光照模型的逐顶点实现,和兰伯特一模一样,唯一的区别就是公式:

Color漫反射光照=Color光源×Color材质的漫反射×((标准化后物体表面法线向量标准化后光源方向向量)×0.5+0.5)Color_{漫反射光照} = Color_{光源} \times Color_{材质的漫反射} \times ((\overrightarrow{标准化后物体表面法线向量} \cdot \overrightarrow{标准化后光源方向向量}) \times 0.5 + 0.5)

具体Shader实现:

要注意,尽管半兰伯特光照模型改进了背光面的显示效果,我们为了光照效果更加自然还是会使用 UNITY_LIGHTMODEL_AMBIENT

不使用 UNITY_LIGHTMODEL_AMBIENT​ (左)和使用 UNITY_LIGHTMODEL_AMBIENT​ (右)的显示区别对比如下:

imageimage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Shader "TeachShader/Lesson32"
{
Properties
{
_MainColor("MainColor", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags { "LightMode" = "ForwardBase" }

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"
#include "Lighting.cginc"

fixed4 _MainColor; //材质的漫反射颜色

struct v2f
{
float4 pos : SV_POSITION;
fixed3 color : COLOR; //这里只传递颜色的rgb,而不传递透明度,故使用fixed3
};

v2f vert (appdata_base v)
{
v2f v2fData;
v2fData.pos = UnityObjectToClipPos(v.vertex); //首先将模型空间下的顶点转换到裁剪空间下

float3 normal = UnityObjectToWorldNormal(v.normal); //将模型空间下的法线转换到世界空间下
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz); //光源0在世界坐标系下的位置标准化,用于和法线计算夹角
//半兰伯特光照模型的实现,这里的颜色计算只取rgb,不考虑透明度的情况
fixed3 color = _LightColor0.rgb * _MainColor.rgb * ((dot(normal, lightDir)) * 0.5 + 0.5);
v2fData.color = UNITY_LIGHTMODEL_AMBIENT + color; //为了让物体看起来更自然,还是需要加上兰伯特环境光颜色公共变量

return v2fData;
}

fixed4 frag (v2f i) : SV_Target
{
return fixed4(i.color.rgb, 1); //因为传递过来的颜色变量不包括透明度,因此这里需要手动指定透明度
}
ENDCG
}
}
}

左图为使用半兰伯特光照模型Shader的材质显示效果,右图为使用兰伯特光照模型Shader的材质显示效果:

imageimage

可见,使用半兰伯特光照模型的材质会更亮一些,阴影处的材质也可以看的更清楚