本文展示实现标准光照模型(只关心场景里最亮的那一个平行光光源)下的光照效果。即自发光(Emissive)、环境光(Ambient)、漫反射(Diffuse)、高光(Specular)这四种光效的叠加,其中高光有两种实现方式Phong和Blinn-Phong,选择调用方法即可。
下面介绍面板参数:
_XXX_Color表示材质反射该光照的颜色,如果是黑色则表示忽略该光照;
_Calculate_Vertex决定使用顶点光照还是像素光照(大于1还是小于1);
_Lambert_Enhance是漫反射光照增强,如果值为0.5,就是常说的Half Lambert光照模型;
_Gloss是高光反射扩散度,值越小光斑越大。
下面分别是顶点光照和像素光照的效果:
最后上Shader代码:
Shader "Test/S001"
{
Properties
{
_Calculate_Vertex ("_Calculate_Vertex", Range (0, 2)) = 0
_Emissive_Color("_Emissive_Color", Color) = (1, 1, 1, 1)
_Ambient_Color("_Ambient_Color", Color) = (1, 1, 1, 1)
_Diffuse_Color("_Diffuse_Color", Color) = (1, 1, 1, 1)
_Specular_Color("_Specular_Color", Color) = (1, 1, 1, 1)
_Lambert_Enhance ("_Lambert_Enhance", Range (-1, 1)) = 0
_Gloss ("_Gloss", Range (1, 256)) = 1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed3 wnormal : TEXCOORD4;
float4 wvertex : TEXCOORD5;
float2 uv : TEXCOORD0;
fixed3 cFinal : COLOR0;
fixed3 cVertex : COLOR1;
fixed3 cEmissive : COLOR2;
fixed3 cAmbient : COLOR3;
fixed3 cDiffuse : COLOR4;
fixed3 cSpecular : COLOR5;
};
fixed4 _Emissive_Color;
fixed4 _Ambient_Color;
fixed4 _Diffuse_Color;
fixed4 _Specular_Color;
fixed _Lambert_Enhance;
half _Gloss;
int _Calculate_Vertex;
//---------------------------------------------------------------------------------------------------------------------------------
fixed3 CalculateEmissiveColor()
{
return _Emissive_Color;
}
fixed3 CalculateAmbientColor()
{
return UNITY_LIGHTMODEL_AMBIENT * _Ambient_Color;
}
fixed3 CalculateDiffuseColor(float3 normalDir, float3 lightDir, fixed3 lightColor, fixed3 diffuseColor)
{
return saturate(dot(normalize(normalDir), normalize(lightDir)) * (1 - _Lambert_Enhance) + _Lambert_Enhance) * lightColor * diffuseColor;
}
fixed3 CalculateSpecularColor_Phong(float3 normalDir, float3 lightDir, float3 viewDir, fixed3 lightColor, fixed3 specularColor)
{
normalDir = normalize(normalDir);
lightDir = normalize(lightDir);
viewDir = normalize(viewDir);
float3 reflectDir = normalize(dot(normalDir, lightDir) * 2 * normalDir - lightDir);
//reflectDir = normalize(reflect(-lightDir, normalDir)); 同上.
return pow(saturate(dot(reflectDir, viewDir)), _Gloss) * lightColor * specularColor;
}
fixed3 CalculateSpecularColor_BlinnPhong(float3 normalDir, float3 lightDir, float3 viewDir, fixed3 lightColor, fixed3 specularColor)
{
normalDir = normalize(normalDir);
lightDir = normalize(lightDir);
viewDir = normalize(viewDir);
float3 midDir = normalize(lightDir + viewDir);
return pow(saturate(dot(midDir, normalDir)), _Gloss) * lightColor * specularColor;
}
//---------------------------------------------------------------------------------------------------------------------------------
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.cVertex = v.color;
float3 wnormal = mul(unity_ObjectToWorld, v.normal);
float3 wvertex = mul(unity_ObjectToWorld, v.vertex);
if (_Calculate_Vertex > 0)
{
o.cEmissive = CalculateEmissiveColor();
o.cAmbient = CalculateAmbientColor();
o.cDiffuse = CalculateDiffuseColor(wnormal, _WorldSpaceLightPos0, _LightColor0, _Diffuse_Color);
o.cSpecular = CalculateSpecularColor_BlinnPhong(wnormal, _WorldSpaceLightPos0, _WorldSpaceCameraPos.xyz - wvertex, _LightColor0, _Specular_Color);
o.cFinal = o.cEmissive + o.cAmbient + o.cDiffuse + o.cSpecular;
}
o.wnormal = wnormal;
o.wvertex = float4(wvertex, 1);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 wnormal = normalize(i.wnormal);
float3 wvertex = i.wvertex;
if (_Calculate_Vertex < 1)
{
i.cEmissive = CalculateEmissiveColor();
i.cAmbient = CalculateAmbientColor();
i.cDiffuse = CalculateDiffuseColor(wnormal, _WorldSpaceLightPos0, _LightColor0, _Diffuse_Color);
i.cSpecular = CalculateSpecularColor_BlinnPhong(wnormal, _WorldSpaceLightPos0, _WorldSpaceCameraPos.xyz - wvertex, _LightColor0, _Specular_Color);
i.cFinal = i.cEmissive + i.cAmbient + i.cDiffuse + i.cSpecular;
}
return fixed4(i.cFinal, 1);
}
ENDCG
}
}
}
参考:《Unity Shader 入门精要》,感谢作者妹子。