US3S1L2-1——兰伯特光照模型的逐顶点光照
US3S1L2-1——兰伯特光照模型的逐顶点光照
知识回顾
兰伯特光照模型公式:
其中, 等于物体表面法线与光源方向向量的夹角的 值
会使用的信息:
光源的颜色
Lighting.cginc
内置文件中的_LightColor0
光源的方向
_WorldSpaceLightPos0
表示光源0在世界坐标系下的位置向量归一化(标准化)方法
normalize()
取最大值方法
max()
点乘方法
dot
兰伯特光照模型环境光变量(用于模拟环境光对物体的影响,避免物体阴影部分完全黑暗)
UNITY_LIGHTMODEL_AMBIENT.rgb
将法线从模型空间转换到世界空间
UnityObjectToWorldNormal
利用兰伯特光照模型实现光照效果(逐顶点光照)
关键步骤:
-
材质漫反射颜色属性声明
1
2
3
4Properties
{
_MainColor("MainColor", Color) = (1, 1, 1, 1)
} -
渲染标签 Tags 设置:将 LightMode 光照模式 设置为 ForwardBase 向前渲染(通常用于不透明物体的基本渲染)
1
Tags { "LightMode"="ForwardBase" }
-
引用内置文件 UnityCG.cginc 和 Lighting.cginc
1
2 -
结构体声明
对于输入到顶点着色器的参数,可以直接使用
UnityCG.cginc
的 appdata_base对于从顶点着色器输出到片元着色器的参数,需要我们自己声明结构体
v2f
1
2
3
4
5struct v2f
{
float4 pos : SV_POSITION;
fixed3 color : COLOR; //这里只传递颜色的rgb,而不传递透明度,故使用fixed3
}; -
基于公式实现逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21fixed4 _MainColor; //材质的漫反射颜色
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 * max(0, dot(normal, lightDir));
v2fData.color = color; //将计算完毕的颜色赋值给结构体成员
return v2fData; //将顶点着色器计算结果传递给片元着色器
}
fixed4 frag (v2f i) : SV_Target
{
return fixed4(i.color.rgb, 1); //因为传递过来的颜色变量不包括透明度,因此这里需要手动指定透明度
}
使用这样的Shader的材质显示效果如下:
可以看到,被光源照射到的地方会显示颜色,而阴影部分是全黑的
注意:为了阴影出不全黑,需要加上兰伯特环境光颜色公共变量 UNITY_LIGHTMODEL_AMBIENT
1 | v2f vert (appdata_base v) |
使用这样的Shader的材质显示效果如下:
可以看到,阴影部分不再是全黑色的
完整的Shader代码如下:
1 | Shader "TeachShader/Lesson29" |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 文KRIFE齐的博客!