先上效果图
改变光线角度得到2副图。
每幅图中的4副图分别为
左上:顶点着色器中兰伯特公式计算
右上:片元着色器中兰伯特公式计算
左下:顶点着色器中半兰伯特公式计算
右下:片元着色器中半兰伯特公式计算
下面讲原理
漫反射
平行光线射到凹凸不平的表面上,反射光线射向各个方向,这种反射叫做漫反射。
兰伯特定律(Lambert's law)
漫反射符合兰伯特定律:反射光线的强度与表面法线和光源方向之间夹角的余弦值成正比。
很明显,冬天没有夏天光线强的也是因为冬天的cosθx小于夏天的cosθ,
冬天θ>夏天θ
=> 冬天cosθ<夏天cosθ
=> 冬天光线 < 夏天光线
=> 冬冷夏热
公式如下:
Cdiffuse = (Clight*Mdiffuse)*max(0, N•L)
其中Cdiffuse代表漫反射后的颜色
Clight代表入射光的颜色
Mdiffuse代表材质颜色
N和L都是单位向量
分析公式可看出θ>=90度 (N•L<=0)时 Cdiffuse的值<=0,那么背光面都为黑漆漆。
因此,提出了一个改良公式:半兰伯特光照模型
公式如下
Cdiffuse = (Clight*Mdiffuse)*((0, N•L) * 0.5 + 0.5)
只有完全背光面(N•L=-1)时Cdiffuse 才会为0
核心代码如下:
fixed3 worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * saturate(dot(worldNormal, worldLight));
fixed3 diffuse = _LightColor0.rgb * (dot(worldNormal, worldLight) * 0.5 + 0.5);
o.color = diffuse;
shader代码如下:
Shader "mgo/study/lambert_vertex"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float2 uv : TEXCOORD0;
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
fixed3 color : COLOR;
};
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
fixed3 worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * saturate(dot(worldNormal, worldLight));
o.color = diffuse;
//fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//o.color = o.color + ambient;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 color = tex2D(_MainTex, i.uv);
color.rgb = color.rgb * i.color;
return color;
}
ENDCG
}
}
}
Shader "mgo/study/lambert_fragment"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float2 uv : TEXCOORD0;
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD1;
};
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 color = tex2D(_MainTex, i.uv);
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * saturate(dot(worldNormal, worldLight));
color.rgb *= diffuse;
//fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//color.rgb = color.rgb + ambient;
return color;
}
ENDCG
}
}
}
Shader "mgo/study/half_lambert_vertex"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float2 uv : TEXCOORD0;
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
fixed3 color : COLOR;
};
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
fixed3 worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * (dot(worldNormal, worldLight) * 0.5 + 0.5);
o.color = diffuse;
//fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//o.color = o.color + ambient;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 color = tex2D(_MainTex, i.uv);
color.rgb = color.rgb * i.color;
return color;
}
ENDCG
}
}
}
Shader "mgo/study/half_lambert_fragment"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float2 uv : TEXCOORD0;
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD1;
};
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 color = tex2D(_MainTex, i.uv);
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * (dot(worldNormal, worldLight) * 0.5 + 0.5);
color.rgb *= diffuse;
//fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
//color.rgb = color.rgb + ambient;
return color;
}
ENDCG
}
}
}