漫反射光照是用于被物体表面随机散射到各个方向的辐射度进行的建模,也被称为兰伯特光照模型。在漫反射中视角的位置是不重要的,因为反射是完全随机的,所以在任何反射方向都是随机的。但是入射光线的角度很重要。
漫反射光照符合兰伯特定律:反射光线的强度 与 表面法线和光源方向之间 的夹角 的余弦值成正比。
漫反射计算公式:(C
* M
)max(0,
)
n:表面法线,l:指向光源的单位矢量,Mdiffuse:材质漫反射颜色,Clight: 光源颜色
max 函数:防止光源方向和法线 点乘为负值。(防止物体被来自后方的光源照亮)== CG中的 saturate(x)函数,截取x在[0,1]范围内,如果x 是矢量,则会对它的每一个分量进行操作。
1.逐顶点光照
Shader "Custom/DiffuseVertex"
{
Properties
{
//默认颜色属性
_DiffuseColor("Color",Color)=(1.0,1.0,1.0,1.0)
}
SubShader
{
pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _DiffuseColor;
struct a2v
{
//顶点位置
float4 vertPos:POSITION;
//法线
float3 normal:NORMAL;
};
struct v2f
{
//剪裁空间顶点位置
float4 pos :SV_POSITION;
//存储光照颜色
fixed3 color:COLOR;
};
v2f vert(a2v v)
{
v2f o;
//模型空间 到剪裁空间
o.pos=UnityObjectToClipPos(v.vertPos);
//获取环境光
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
//转换法线方向到世界空间 并归一化
fixed3 worldNormal=normalize(mul(v.normal,(float3x3)unity_WorldToObject));
//假设场景只有一个平行光,获取光源方向
fixed3 worldLight=normalize(_WorldSpaceLightPos0.xyz);
//_LightColor0 内置变量 获取 该Pass处理的光源的颜色和强度
//利用漫反射公式计算
fixed3 diffuse=_LightColor0.rgb*_DiffuseColor.rgb*saturate(dot(worldNormal,worldLight));
//加上环境光
o.color=ambient+diffuse;
return o;
}
fixed4 frag(v2f i):SV_Target
{
return fixed4(i.color,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
对于细分度高的模型,可以得到很好的光照效果,但是细分度很低的就会有些问题。此时模型在背光面和向光面 会出现锯齿。
2.逐像素光照
将计算漫反射部分放入片元函数中
Shader "Custom/DiffuseFragment"
{
Properties
{
_DiffuseColor("Color",Color)=(1.0,1.0,1.0,1.0)
}
SubShader
{
pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _DiffuseColor;
struct a2v
{
float4 vertPos:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos :SV_POSITION;
float3 normalWorld:TEXCOORD0;
};
v2f vert(a2v v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertPos);
o.normalWorld=mul(v.normal,(float3x3)unity_WorldToObject);
return o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal=normalize(i.normalWorld);
fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse=_LightColor0.rgb*_DiffuseColor.rgb*saturate(dot(worldNormal,worldLightDir));
return fixed4(ambient+diffuse,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
此时的模型就没有那些锯齿状了。
锯齿状虽然解决了,但是模型的背光面,看起来像是一个平面,对于其他复杂的模型来说,失去了细节表现。