US3S1L2-2——兰伯特光照模型的逐片元光照
知识回顾
兰伯特光照模型公式:
Color漫反射光=Color光源×Color材质的漫反射×max(0,标准化后物体表面法线向量⋅标准化后光源方向向量)
其中,标准化后物体表面法线向量⋅标准化后光源方向向量 等于物体表面法线与光源方向向量的夹角的 cos 值
会使用的信息:
-
光源的颜色
Lighting.cginc
内置文件中的 _LightColor0
-
光源的方向
_WorldSpaceLightPos0
表示光源0在世界坐标系下的位置
-
向量归一化(标准化)方法 normalize()
-
取最大值方法 max()
-
点乘方法 dot
-
兰伯特光照模型环境光变量(用于模拟环境光对物体的影响,避免物体阴影部分完全黑暗)
UNITY_LIGHTMODEL_AMBIENT.rgb
-
将法线从模型空间转换到世界空间 UnityObjectToWorldNormal
利用兰伯特光照模型实现光照效果(逐片元光照)
关键步骤:基本和逐顶点一致
区别:
- 在顶点着色器中计算顶点(转换到裁剪空间)和法线(转换到世界空间)
- 在片元着色器中计算兰伯特光照
Shader实现如下:
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
| Shader "TeachShader/Lesson30" { 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; float3 normal : NORMAL; };
v2f vert (appdata_base v) { v2f v2fData; v2fData.pos = UnityObjectToClipPos(v.vertex); v2fData.normal = UnityObjectToWorldNormal(v.normal); return v2fData; }
fixed4 frag (v2f i) : SV_Target { float3 lightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 color = _LightColor0.rgb * _MainColor.rgb * max(0, dot(i.normal, lightDir)); color = UNITY_LIGHTMODEL_AMBIENT.rgb + color; return fixed4(color.rgb, 1); } ENDCG } } }
|
使用逐顶点光照和逐片元光照的Shader的材质显示效果如下(左边为逐顶点光照,右边为逐片元光照):
显然,使用逐片元光照的Shader的材质在阴影处的过渡效果,比逐顶点光照的效果更柔和一些