US3S1L4-2——Phong式高光反射光照模型的逐片元光照

知识回顾

公式:

高光反射光照颜色=光源的颜色×材质高光反射颜色×max(0, 标准化后观察方向向量标准化后的反射方向)光泽度高光反射光照颜色 = 光源的颜色 \times 材质高光反射颜色 \times \max(0,\ \overrightarrow{标准化后观察方向向量} \cdot \overrightarrow{标准化后的反射方向})^{光泽度}

  1. 标准化后观察方向向量标准化后的反射方向\overrightarrow{标准化后观察方向向量} \cdot \overrightarrow{标准化后的反射方向} 得到的结果就是 cosθ\cos\theta
  2. 光泽度是幂运算,相当于:(max(0,cosθ))n(max(0,\cos\theta))^n

信息获取:

  1. 观察者的位置(摄像机的位置):_WorldSpaceCameraPos
  2. 相对于法向量的反射向量 方法:reflect(入射向量, 顶点法向量)​ 返回反射向量
  3. 指数幂 方法:pow(底数, 指数)​ 返回计算结果

其他关键信息获取方式和兰伯特光照模型差不多,参考:如何在Shader中获取公式中的关键信息

利用Phong式高光反射模型实现光照效果(逐片元光照)

关键步骤:基本和逐顶点一致

区别:

  1. 在顶点着色器计算顶点和法线相关数据
  2. 在片元着色器中计算Phong式高光反射光照

Shader实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Shader "Unlit/Lesson36"
{
Properties
{
_SpecularColor("SpecularColor", Color) = (1, 1, 1, 1) //材质高光反射颜色
_SpecularNum("SpecularNum", Range(0, 20)) = 0.5 //光泽度
}
SubShader
{
Pass
{
Tags { "LightMode" = "ForwardBase" } //如果有多个Pass,则一般将光照模式的Tag放到对应的Pass中,以免影响其他Pass

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"
#include "Lighting.cginc"

struct v2f
{
float4 svPos : SV_POSITION; //裁剪空间下的顶点坐标
float3 wNormal : NORMAL; //世界空间下的法线
float3 wPos : TEXCOORD0; //世界空间下的顶点坐标
};

fixed4 _SpecularColor;
float _SpecularNum;

v2f vert (appdata_base v)
{
v2f v2fData;
v2fData.svPos = UnityObjectToClipPos(v.vertex); //顶点转换到裁剪空间
v2fData.wNormal = UnityObjectToWorldNormal(v.normal); //法线转换到世界空间
v2fData.wPos = mul(unity_ObjectToWorld, v.vertex).xyz; //顶点转换到世界空间

return v2fData;
}

fixed4 frag (v2f i) : SV_Target
{
float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.wPos); //计算观察方向
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz); //标准化光源方向
float3 reflectDir = reflect(-lightDir, i.wNormal); //计算反射光线向量,需要对光源方向取反
//Phong高光反射模型的实现,这里的颜色计算只取rgb,不考虑透明度的情况
fixed3 color = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(viewDir, reflectDir)), _SpecularNum);
return fixed4(color.rgb, 1);
}
ENDCG
}
}
}

显示效果(左边为逐片元光照,右边为逐顶点光照):

image

显然,逐片元光照的效果更平滑