Unityシェーダー:PhongShader

Unityで開発したシンプルなPhongShader.
Phongシェーディング

Lambertシェーディングの式に加えて鏡面反射項が加わります.鏡面反射モデルとしては,Blinn–Phongのモデルもありますが,今回は,Phongのモデルを鏡面反射の計算に使います.

Phongのモデルでは,ライトベクトル$\mathbf{L}$と視線ベクトルの正反射ベクトル$\mathbf{RV}$との内積で鏡面反射を計算します.鏡面反射の色$\mathbf{c_s}$,鏡面反射率$k_s$,ハイライトの鋭さ$\alpha$を用いると,最終的な色は,以下の計算式で表現されます.
$I = k_a \mathbf{c_a} + k_d (\mathbf{L} \cdot \mathbf{N}) \mathbf{c_d} + k_s (\mathbf{L} \cdot \mathbf{RV})^{\alpha} \mathbf{c_s} $

PhongShader.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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Pixel処理でシェーディング計算を行うPhongShader
Shader "Custom/PhongShader" {
// PhongShaderのパラメータを宣言
Properties {
// 環境光の色
// _Ka: 反射率
_Ambient ("Ambient Color", Color) = (0.3,0.3,1,1)
_Ka ("Ka", Range (0.01, 1)) = 0.5
// 拡散反射の色
// _Kd: 反射率
_Diffuse ("Diffuse Color", Color) = (0.3,0.3,1,1)
_Kd ("Kd", Range (0.01, 1)) = 0.8
// 鏡面反射の色
// _Ks: 反射率
// _Shininess: ハイライトの鋭さ
_Specular ("Spec Color", Color) = (1,1,1,1)
_Ks ("Ks", Range (0.01, 1)) = 1.0
_Shininess ("Shininess", Range (0.01, 1)) = 0.7
}
SubShader {
pass{
// Unityのライトオブジェクトを使ったLightMode
Tags { "LightMode" = "ForwardBase" }
// Cgプログラムを使用する宣言
// 頂点処理とピクセル処理を行うことを宣言
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// Cgプログラムで使う変数
// Propertiesブロックと対応付ける
float4 _Ambient;
float _Ka;
float4 _Diffuse;
float _Kd;
float4 _Specular;
float _Ks;
float _Shininess;
// 頂点からピクセルに転送されるデータ
struct vertexOutput {
float4 pos : SV_POSITION; // 座標変換後の位置
float3 L : TEXCOORD0; // ライトベクトル
float3 N : TEXCOORD1; // 法線ベクトル
float3 RV : TEXCOORD2; // 視線の正反射ベクトル
};
// 頂点毎の処理
// pos, L, N, RVのデータを計算する.
vertexOutput vert(appdata_base v) : POSITION
{
vertexOutput output;
// 座標変換後の位置
output.pos = mul (UNITY_MATRIX_MVP, v.vertex);
// 法線ベクトル
float3 N = v.normal;
output.N = N;
// ライトベクトル
output.L = ObjSpaceLightDir(v.vertex);
// 視線の正反射ベクトル
float3 V = ObjSpaceViewDir(v.vertex);
output.RV = reflect(-V, N);
return output;
}
// ピクセル毎の処理
// PhongShadingのライティング計算を行う
float4 frag(vertexOutput input) : COLOR
{
// 頂点処理で計算したベクトルデータを正規化して取り出す
float3 L = normalize( input.L );
float3 N = normalize( input.N );
float3 RV = normalize( input.RV );
// 環境光成分I_aを計算
float4 I_a = _Ka * _Ambient;
// 拡散反射成分I_dを計算
float LdN = clamp( dot(L, N), 0, 1 );
float4 I_d = _Kd * LdN * _Diffuse;
// 鏡面反射成分I_sを計算
float LdRV = clamp( dot(L, RV), 0, 1 );
float shininess = pow(500.0, _Shininess);
float4 I_s = _Ks * pow( LdRV, shininess) * _Specular;
// 足し合わせて最終的な色を計算する
float4 I = I_a + I_d + I_s;
return I;
}
ENDCG
}
}
FallBack "Diffuse"
}

参考文献

[1] Phong Reflection Model - Wikipedia: http://en.wikipedia.org/wiki/Phong_reflection_model
[2] Blinn–Phong shading model - Wikipedia: http://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model