1、原理
物体表面反射光线是由三部分组成:环境光 + 漫反射光 + 镜面反射光(高光反射光)
2、公式
物体表面光照颜色 = 环境光颜色 + 漫反射光颜色 + 高光反射光颜色
其中:
- 环境光颜色 = UNITY_LIGHTMODEL_AMBIENT(unity_AmbientSky、unity_AmbientEquator、unity_AmbientGround)
- 漫反射光颜色 =【兰伯特光照模型】计算得到的颜色
- 高光反射光颜色 =【Blinn Phong式高光反射光照模型】计算得到的颜色
3、逐顶点光照
Shader "ShaderProj/1/Blinn_Phong_vertex"
{
Properties
{
_MainColor("_MainColor", Color)=(1,1,1,1)
_SpecularColor("_SpecularColor", Color)=(1,1,1,1)
_SpecularNum("_SpecularNum", Range(0, 20))=5
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float4 pos:SV_POSITION;
fixed3 color:COLOR;
};
fixed3 _MainColor;
fixed3 _SpecularColor;
float _SpecularNum;
fixed3 getLambertColor(float3 wNormal, float lightDir)
{
fixed3 color = _LightColor0 * _MainColor * max(0, dot(wNormal, lightDir));
return color;
}
// PS:一定要把参数的类型传对,这里把 vertex 传成了 float3 类型,导致 worldPos 的结果是错的
// 最终高亮的位置不对
fixed3 getSpecularColor(float4 vertex, float3 wNormal, float3 lightDir)
{
float3 worldPos = mul(unity_ObjectToWorld, vertex);
float3 viewDir = normalize(_WorldSpaceCameraPos - worldPos);
float3 halfAngle = normalize(viewDir + lightDir);
fixed3 color = _LightColor0 * _SpecularColor * pow(max(0, dot(wNormal, halfAngle)), _SpecularNum);
return color;
}
v2f vert (appdata_base v)
{
v2f data;
data.pos = UnityObjectToClipPos(v.vertex);
float3 normal = UnityObjectToWorldNormal(v.normal);
float3 lightDir = normalize(_WorldSpaceLightPos0);
// lambert
fixed3 lambertColor = getLambertColor(normal, lightDir);
// specular
fixed3 specularColor = getSpecularColor(v.vertex, normal, lightDir);
//fixed3 specularColor = getSpecularColor(v.vertex, v.normal);
data.color = lambertColor + specularColor + UNITY_LIGHTMODEL_AMBIENT;
return data;
}
fixed4 frag (v2f i) : SV_Target
{
return fixed4(i.color, 1);
}
ENDCG
}
}
}
4、逐片元光照
Shader "ShaderProj/1/Blinn_Phong_frag"
{
Properties
{
_MainColor("_MainColor", Color)=(1,1,1,1)
_SpecularColor("_SpecularColor", Color)=(1,1,1,1)
_SpecularNum("_SpecularNum", Range(0,20))=5
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct v2f
{
float4 pos:SV_POSITION;
float3 normal:NORMAL;
float3 wPos:TEXCOORD0;
};
fixed3 _MainColor;
fixed3 _SpecularColor;
float _SpecularNum;
fixed3 getLambertColor(float3 normal, float3 lightDir)
{
fixed3 color = _LightColor0 * _MainColor * max(0, dot(lightDir, normal));
return color;
}
fixed3 getSpecularColor(float3 worldPos, float3 normal, float3 lightDir)
{
float3 viewDir = normalize(_WorldSpaceCameraPos - worldPos);
float3 halfAngle = normalize(viewDir + lightDir);
fixed3 color = _LightColor0 * _SpecularColor * pow(max(0, dot(normal, halfAngle)), _SpecularNum);
return color;
}
v2f vert (appdata_base v)
{
v2f data;
data.pos = UnityObjectToClipPos(v.vertex);
data.wPos = mul(unity_ObjectToWorld, v.vertex);
data.normal = UnityObjectToWorldNormal(v.normal);
return data;
}
fixed4 frag (v2f i) : SV_Target
{
float3 lightDir = normalize(_WorldSpaceLightPos0);
fixed3 lambertColor = getLambertColor(i.normal, lightDir);
fixed3 specularColor = getSpecularColor(i.wPos, i.normal, lightDir);
fixed3 color = UNITY_LIGHTMODEL_AMBIENT + lambertColor + specularColor;
return fixed4(color, 1);
}
ENDCG
}
}
}
5、单张纹理结合BlinnPhong光照模型
在计算时,有以下的3点注意点
- 纹理颜色需要和漫反射颜色进行乘法叠加, 它们两共同影响最终的颜色
- 兰伯特光照模型计算时,漫反射材质颜色使用 1 中的叠加颜色计算
- 最终使用的环境光叠加时,环境光变量UNITY_LIGHTMODEL_AMBIENT需要和 1 中颜色进行乘法叠加,为了避免最终的渲染效果偏灰
Shader "ShaderProj/2/Texture_LightMode"
{
Properties
{
_MainTex("_MainTex", 2D) = ""{}
_MainColor("_MainColor", Color) = (1,1,1,1)
_SpecularColor("_SpecularColor", Color) = (1,1,1,1)
_SpecularNum("_SpecularNum", Range(0,20)) = 15
}
SubShader
{
Tags { "LightMode"="ForwardBase" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _MainColor;
fixed4 _SpecularColor;
float _SpecularNum;
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
float3 wNormal:NORMAL;
float3 wPos:TEXCOORD01;
};
fixed3 getLambertColor(float3 normal, float3 lightDir, fixed3 albedo)
{
fixed3 color = _LightColor0 * albedo * max(0, dot(lightDir, normal));
return color;
}
fixed3 getSpecularColor(float3 worldPos, float3 normal, float3 lightDir)
{
//float3 viewDir = normalize(_WorldSpaceCameraPos - worldPos);
float3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
float3 halfAngle = normalize(viewDir + lightDir);
fixed3 color = _LightColor0 * _SpecularColor * pow(max(0, dot(normal, halfAngle)), _SpecularNum);
return color;
}
v2f vert (appdata_base v)
{
v2f data;
data.pos = UnityObjectToClipPos(v.vertex);
data.wNormal = UnityObjectToWorldNormal(v.normal);
data.wPos = mul(unity_ObjectToWorld, v.vertex);
data.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
//data.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
return data;
}
fixed4 frag (v2f i) : SV_Target
{
// 纹理颜色需要和漫反射材质颜色叠加(乘法)共同决定最终的颜色
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _MainColor.rgb;
float3 lightDir = normalize(_WorldSpaceLightPos0);
fixed3 lambertColor = getLambertColor(i.wNormal, lightDir, albedo);
fixed3 specularColor = getSpecularColor(i.wPos, i.wNormal, lightDir);
// 环境光也要与纹理颜色叠加,防止变灰
fixed3 color = lambertColor + specularColor + UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
return fixed4(color, 1);
}
ENDCG
}
}
}