フォンの反射モデル
フォンの反射モデルとは
ランバート反射モデルにスペキュラ反射を追加したものです。
スペキュラ反射
物体表面のハイライト(光沢)部分を表現するものです。
プラスチックや金属を見ると表面の一部に強いハイライトが発生しているあれです。
ハイライトは、サーフェスに対する視点の向きに応じて位置や大きさが変わります。
ですから、向きに依存せず同じ値を返すランバート反射モデルでは表現できません。
そこで反射色という概念を導入し、拡散色に加算してハイライトを表現します。
スペキュラ反射はこの反射色を計算するものです。
ただし、アルタイムレンダリングにおけるスペキュラ反射は、実際に光源の姿を映り込ませているわけではなく、それっぽいハイライトを描画する近似処理になります。
スペキュラ反射の反射量 = ( V・R )^n
V = 視点方向ベクトル
R = 反射ベクトル
n = 光沢度
( V・R )
視点方向ベクトルと反射ベクトルとの内積を計算しています。これは、視点と光源の方向が近いほどスペキュラ反射は強くなり、離れるほど弱くなるという観察による現象を再現した物です。
^n
内積の結果をn乗した物がスペキュラ反射量になります。このnは光沢度(shininess)と言って、 表面の光沢具合を示す値です。
反射は表面がツルツルなほどハイライトは強くなり、範囲が小さくなります。逆に表面がザラザラなほど、ハイライトは弱くなり、範囲は広がります。
この変化は指数的に変化するため光沢度を乗数として使用しています。
反射ベクトルの求め方
当たり判定などでもよく計算する反射ベクトルについて、考えます。
「反射ベクトルと光源方向ベクトルを合成して2で除算したベクトル」と「光源方向ベクトル と法線ベクトルの内積に法線ベクトルを乗算したベクトル」が一致するのでそれを式にすると以下になります。
( R + L ) / 2 = N x ( N ・ L )
R = 反射ベクトル
L = 光源方向ベクトル
N = 法線ベクトル
反射ベクトル以外を右辺に移行します。
R = ( N ・ ( N ・ L ) ) x 2 - L
これが反射ベクトルを求める式になります。
//法線ベクトル float3 normal = normalize(i.worldNormal); //視点方向ベクトル float3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); //法線ベクトルと視点ベクトルの内積 float NdotL = dot(normal, lightDir);
//拡散色
float diffusePower = max( 0, NdotL );
ランバート反射モデルの式です。
//拡散色の決定 float4 diffuse = diffusePower * tex * _LightColor0;
拡散色にテクスチャ色とディレクショナルライトのColorを掛けています。
//フォンによるスペキュラ近似式1 float3 R = -1 * viewDir + 2.0f * NdotV * normal;
先程の式を使って反射ベクトルを求めます。
視点ベクトルに-1を乗算しているのはUnityWorldSpaceViewDirが
視点方向へのベクトルを返すからです。
//フォンによるスペキュラ近似式2 float LdotR = dot(lightDir, R);
float3 specularPower = pow(max(0, LdotR), 10.0);
スペキュラ反射の反射量の計算です。
反射ベクトルと光源方向ベクトルの内積を計算します。この値が 1.0 に近いほど、反射ベクトルと光 源方向ベクトルの向きが近く、光沢が強く現れる所ということななります。
角度に差がないほど光ってみえます。
powは累乗の計算をする関数で光沢度の計算をしています。
//拡散色と反射色を合算
fixed4 color = diffuse + specular; return color;
最後にランバート反射モデルで求めた拡散色とスペキュラ反射の色を合算してその色を返します。
以上がフォンの反射モデルの解説になります。