兰伯特光照模型
n 表面法线
I 指向光源的单位矢量
Mdiffuse 材质的漫反射颜色
Clight 光源颜色
max 防止物体被从后面来的光源照亮,CG 提供了这样的函数 saturate。
函数:saturate(x)描述:把x截取在(0, 1]范围内,如果x是一个矢量,那么会对它的每一个分量进行这样的操作。
半兰伯特光照模型
一般情况下 a,b 均为 0.5,即
通过这样的方式,可以把 n*l 的结果范围从[-1, 1] 映射到 [0, 1] 范围内。对于模型的背光面,在原兰伯特光照模型中点积结果将映射到同一个值,即 0 值处;在半兰伯特模型中,背光面也可以有明暗变化,不同的点积结果会映射到不同的值上。
优缺点
兰伯特光照模型-逐顶点光照
缺点:对于一些细分程度较低的模型,逐顶点光照会在背面光与向光面处有一些锯齿。
兰伯特光照模型-逐像素光照
优点:可以得到更加平滑的光照效果。
缺点:在光照无法到达的区域,模型的外观通常是全黑的,没有任何敏感变化,这会使模型的背光区域看起来就像一个平面一样,失去了模型细节表现。
半兰伯特
背光面也会有明暗变化;
代码实现
// 兰伯特光照模型-逐顶点光照
Shader "Custom/Shader6_1_diffuse"
{
Properties
{
_Duffuse("Diffuse",color) = (1.0,1.0,1.0,1.0)
}
SubShader
{
Tags {"LightMode"="ForwardBase"} // 定义该pass在Unity的光照流水线中的角色,只有正确定义LightMode,才能得到Unty内置光照变量
LOD 200
pass
{
CGPROGRAM
// 漫反射
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Duffuse;
struct a2v{
float4 position:POSITION; // 顶点座标
float3 normal:NORMAL; // 法线
};
struct v2f
{
float4 pos:SV_POSITION;
float3 color:COLOR; // 顶点座标
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.position); // 着色器的基本任务
// 需要把n和l转换到相同的座标系下。世界空间
// 从模型空间变换到世界空间,可以使用顶点变换矩阵的逆转矩阵来对法线进行相同的换算,
// 从模型空间到世界空间变换矩阵的逆矩阵 unity_WorldToObject,通过调换它在mul中的位置,得到和转置矩阵相同的矩阵乘法。
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 diffuse = _LightColor0.rab * _Duffuse.rgb * saturate(dot(worldNormal, worldLight));
o.color = ambient + diffuse;
return o;
}
fixed4 frag(v2f v):SV_Target
{
return fixed4(v.color, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
// 兰伯特光照模型-逐像素光照
Shader "Custom/Shader6_1_diffuse"
{
Properties
{
_Diffuse("Diffuse",color) = (1.0,1.0,1.0,1.0)
}
SubShader
{
Tags {"LightMode"="ForwardBase"}
LOD 200
pass
{
CGPROGRAM
// 漫反射
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
struct a2v
{
float4 position:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 nor:TEXCOORD0; // 法线
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.position); // 顶点座标变换到裁剪空间
o.nor = v.normal;
return o;
}
fixed4 frag(v2f v):SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(mul(v.nor, (fixed3x3)unity_WorldToObject));
fixed3 worldLight = normalize(_WorldSpaceLightPos0);
fixed3 diffsue = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
return fixed4(ambient + diffsue, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
//半兰伯特
Shader "ZJT/Shader06-half"
{
Properties
{
_Diffuse ("Diffuse", Color) = (1.0, 1.0, 1.0, 1.0)
}
SubShader
{
Tags{"RenderType"="Opaque"}
LOD 200
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag(v2f v):SV_Target
{
fixed3 worldNormal = normalize(v.worldNormal);
fixed3 worlfLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (0.5 + 0.5 * dot(worldNormal, worlfLightDir));
return fixed4(ambient + diffuse, 1);
}
ENDCG
}
}
}