前情提要:前面一节的漫反射实际上是根据兰伯特光照模型来进行实现的
但这种做法有个缺点就是顶点法线和光的夹角大于90度的时候的成色是完全黑的这和我们生活中见到的事物是不一样的。所以就有了新的光照模型------半兰伯特光照模型。
对比:
兰伯特:
- Diffuse = 直射光颜色 * max(0,cosθ(光和法线夹角))
半兰伯特:
- Diffuse = 直射光颜色 * (cosθ(光和法线夹角) *0.5 + 0.5)
shader实现:
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Custom/MyDiffuseShader-Frag-HalfLambert"
{
Properties
{
_Diffuse("Diffuse color",Color) = (1,1,1,1)
}
SubShader
{
pass
{
Tags { "LightMode"="ForwardBase" }
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0 第一个直射光的位置
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
fixed3 worldNormalDir:color;
};
v2f vert(a2v i)
{
v2f o;
o.pos = UnityObjectToClipPos(i.vertex);
o.worldNormalDir = mul(i.normal,(float3x3)unity_WorldToObject);
return o;
}
float4 frag(v2f i):SV_TARGET
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;//获取环境光
fixed3 normalDir = normalize(i.worldNormalDir); //这个矩阵把一个方向从世界空间转换到模型空间 这样放在后面就是模型到世界了
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说光的位置就是光的方向,因为光是平行的。
fixed3 halfLambert = dot(normalDir,lightDir) * 0.5 + 0.5; //半兰伯特光照公式
fixed3 diffuse = _LightColor0.rgb * halfLambert * _Diffuse;//取得漫反射的颜色
fixed3 tempColor = diffuse + ambient;
return fixed4(tempColor,1);
}
ENDCG
}
}
}
对比于兰伯特,半兰伯特可以看到被光面的细节。