1.漫反射
漫反射光照是用于对于哪些物体表面散射光照进行建模的。
兰伯特定律(Lambert law)和 半兰伯特定律(Half Lambert)都是描述漫反射光照的经验模型。
兰伯特定律:
cDiffuse = cLight * mDiffuse * Max(0,n • l)
cLight 是光源颜色
mDiffuse 是材质球是设置的漫反射颜射
n 为 顶点或者片元法向量 ,l 为指向光源的单位矢量
在书写shader代码时,顶点着色器和片元着色器都可以实现兰伯特定律,顶点着色器写的代码执行效率高,片元着色器片效果会更光滑。
在shader渲染时 片元的个数往往是顶点的几倍所以 顶点效率高,但却没有片元细致
逐顶点、逐片元效果图:
逐顶点代码如下:
///
//简单漫反射
//
Shader "Unlit/BRM01"
{
Properties
{
_Diffuse("Diffuse",Color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
fixed3 color : Color;
float4 vertex : SV_POSITION;
};
fixed4 _Diffuse;
sampler2D _MainTex;
float4 _MainTex_ST;
//顶点着色器
v2f vert (appdata_base v)
{
v2f o;
//物体坐标转裁剪空间坐标
o.vertex = UnityObjectToClipPos(v.vertex);
//物体法线转世界坐标法线
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
//世界左边光源方向
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//漫反射公式
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal , worldLight));
//最终颜色
o.color = diffuse + ambient;
return o;
}
//片元着色器
fixed3 frag (v2f i) : SV_Target
{
return i.color;
}
ENDCG
}
}
}
逐片元代码如下:
//
//简单片元漫反射模型
//
Shader "Unlit/BRM02"
{
Properties
{
_Diffuse("Diffuse",Color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float3 worldNormal : TEXCOORD0;
float4 vertex : SV_POSITION;
};
fixed4 _Diffuse;
sampler2D _MainTex;
float4 _MainTex_ST;
//顶点着色器
v2f vert (appdata_base v)
{
v2f o;
//物体坐标转裁剪空间坐标
o.vertex = UnityObjectToClipPos(v.vertex);
//物体法线转世界坐标法线
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
//片元着色器
fixed3 frag (v2f i) : SV_Target
{
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//世界左边光源方向
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//漫反射
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0,dot(worldLight,i.worldNormal));
//最终颜色
fixed3 color = ambient + diffuse;
return color;
}
ENDCG
}
}
}
半兰伯特定律:
实现完兰伯特定律时我们会发现光照无法直接照射到的位置通常是全黑的,没有任何明暗变化,这会使模型的背光区看起来像一个平面,失去了模型细节的表现。为此半兰伯特光照模型就出现了。
公式:
cDiffuse = cLight * mDiffuse * 0.5 *(n • l) + 0.5
cLight 是光源颜色
mDiffuse 是材质球是设置的漫反射颜射
n 为 顶点或者片元法向量 ,l 为指向光源的单位矢量
因为颜色的范围在[0,1] 、n • l 的范围在[-1,1] 。n • l 小于0的部分会被舍弃 ,所以我们将法向量和光源方向矢量的点积 映射到 [0,1]的范围内。这样背面也可以有明暗变化了。
效果图:
逐片元半兰伯特模型代码:
//
//简单片元漫反射模型
//半兰伯特模型
//
Shader "Unlit/BRM03"
{
Properties
{
_Diffuse("Diffuse",Color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float3 worldNormal : TEXCOORD0;
float4 vertex : SV_POSITION;
};
fixed4 _Diffuse;
sampler2D _MainTex;
float4 _MainTex_ST;
//顶点着色器
v2f vert (appdata_base v)
{
v2f o;
//物体坐标转裁剪空间坐标
o.vertex = UnityObjectToClipPos(v.vertex);
//物体法线转世界坐标法线
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
//片元着色器
fixed3 frag (v2f i) : SV_Target
{
//环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//世界左边光源方向
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
//漫反射 点积为负为背光面
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (dot(worldLight,i.worldNormal) * 0.5 + 0.5);
//最终颜色
fixed3 color = ambient + diffuse;
return color;
}
ENDCG
}
}
}