Shader "Unity Shaders Book/Chapter 6/Diffuse Pixel-Level"
{
Properties
{
_Diffuse ("Diffuse", Color)= (1, 1, 1, 1)//声明一个Color类型的属性,并把它初始值设为白色
}
SubShader{
Pass{
//LightMode标签是Pass标签的一种,它用于定义该Pass在Unity的光照流水线中的角色,
//只有定义了正确的LightMode,我们才能得到一些Unity的内置光照变量
Tags{ "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//包含进Unity的内置文件Lighting.cginc
#include "Lighting.cginc"
#include "UnityCG.cginc"
//为了在Shader中使用Properties语义块中声明的属性,我们需要定义一个和该属性类型相匹配的变量
//由于颜色属性的范围在0到1之间,因此我们可以使用fixed精度的变量来存储它
fixed4 _Diffuse;//材质的漫反射颜色
//定义顶点着色器的输入结构体
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;//这里得到的法线是位于模型空间下的
};
//定义顶点着色器的输出结构体(输出结构体同时也是片元着色器的输入结构体)
struct v2f {
float4 pos : SV_POSITION;
//为了在顶点着色器中计算得到的光照颜色传递给片元着色器,我们在v2f中定义一个worldNormal变量
float3 worldNormal : TEXCOORD0;
};
//顶点着色器不需要计算光照模型,只需要把世界空间下的法线传递给片元着色器即可
v2f vert(a2v v){
v2f o;
//把顶点位置从模型空间转换到剪裁空间中,使用Unity内置的模型*世界*投影矩阵 UNITY_MATRIX_MVP 来完成这样的坐标转换
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//v.normal : 顶点法线
//_World2Object : 模型空间到世界空间的变换矩阵的逆矩阵
//首先得到模型空间到世界空间的变换矩阵的逆矩阵_World2Object,然后通过调转它在mul函数中的位置,得到和转置矩阵相同的矩阵乘法。
//由于法线是一个三维向量,因此我们只需要截取_World2Object的前三行前三列即可
o.worldNormal = mul(v.normal, (float3x3)_World2Object);//得到世界空间下的法线(并未归一化)
return o;
}
//片元着色器需要计算漫反射光照模型
fixed4 frag(v2f i) : SV_Target{
//通过Unity的内置变量UNITY_LIGHTMODEL_AMBIENT得到了环境光部分
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);//得到归一化后的表面法线
//需要注意的是,这里对光源方向的计算并不具有通用性。在本节中,我们假设场景中只有一个光源且光源的类型是平行光。但如
//果场景中有多个光源并且类型可能是点光源等其他类型,直接使用_WorldSpaceLightPos0不能得到正确的结果
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//归一化后的光源方向
//saturate函数是CG提供的一种函数,它的作用是可以把参数截取到[0,1]的范围内,在这里使用这个函数防止点积的结果为负值
//在计算法线和光源方向之间的点积,只有两者处于同一坐标空间下,它们的点积才有意义。在这里,我们把表面法线和光源方向都转换到世界空间
//漫反射部分 = 光源颜色*材质的漫反射颜色*saturate(归一化的表面法线和归一化的光源方向的点积)
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
fixed3 color = ambient + diffuse;
return fixed4(color, 1.0);//输出顶点颜色
}
ENDCG
}
}
Fallback "Diffuse"//把这个Unity Shader的回调shader设置为内置的Diffuse
}
来源于Unity Shader入门精要
与逐顶点光照相比,逐像素光照可以得到更加平滑的光照效果。但是,逐光照漫反射部分或是逐像素漫反射部分都存在一个问题。在光照无法到达的区域,模型的外观通常是全黑的,没有任何明暗变化,这会使模型的背光区域看起来就像一个平面一样,失去了模型细节表现。我们可以通过添加环境光来得到非全黑的效果。但即便是这样仍然无法解决背光面明暗一样的缺点。而半兰伯特(Half Lambert)光照模型因此被提出用于改善这个问题。