概要
- この記事では, Blinn-Phong のスペキュラ計算の正規化について説明しようと思います.
- Blinn-Phong のスペキュラ計算の正規化を行う理由については, スペキュラのライティングにおいてエネルギー保存則を満たすようにするためです.
正規化していない Blinn-Phong スペキュラの計算
- 従来どおりの Blinn-Phong スペキュラの計算方法は下のようになります.
light_specular = light_color * pow( max( 0, dot( normal, half ) ), m );
[GOOD] 正規化した (Blinn-)Phong スペキュラ
- 光のエネルギーの保存則を考えた場合, m の値が増えて スペキュラのハイライト部分が集中すると, その分 ハイライト部分の明るさがより強くなっていくはずです.
- かなり大雑把に説明すると, (エネルギーの総量 : 一定) = (スペキュラのハイライトの領域) * ( スペキュラのハイライトの輝度) となるので, スペキュラのハイライトの面積が減ると, スペキュラのハイライトが明るくなるはずです.
- 下図は正規化された Phong スペキュラの例で, 図の右側へと進み, m の値が増えてスペキュラのハイライトが集中するにつれ, スペキュラが強くなっていることがわかると思います.
[BAD] 正規化していない (Blinn-)Phong スペキュラ
- 一方で, もし正規化していない場合だと下図のように, 図の右側へと進み m の値が増えてスペキュラのハイライトが集中しても, 明るさがあまり変わりません.
Blinn-Phong スペキュラを正規化するには ?
- スペキュラのエネルギーが保存されるようにするには, ハイライトの領域の大小に応じて, ハイライトの輝度を変える必要がありそうです.
- そこで スペキュラのエネルギーが保存されるように正規化した Blinn-Phong スペキュラを計算するには, 正規化係数を乗算します.
- 正規化係数は以下のような式になります.
norm_factor = ( m + 2 ) / ( 2 * PI );
light_specular = light_color * norm_factor * pow( max( 0, dot( normal, half ) ), m );
GLSL シェーダの実装例 : 正規化なしの Blinn-Phong スペキュラ (m=100, m=800)
- ハイライトの領域が小さくなっても, ハイライトの明るさが変わりませんので不自然です.
GLSL シェーダの実装例 : 正規化ありの Blinn-Phong スペキュラ (m=100, m=800)
- ハイライトの領域が小さくなったときに, ハイライトがきちんと明るくなっています.
おまけ : 正規化する前後の Blinn-Phong スペキュラのグラフ
- 下図が正規化係数なしの Blinn-Phong のスペキュラの様子です. m の値の変化に関わらず, 最大値が 1 で固定されていることがわかると思います.
- 一方で下図が, 正規化係数ありの Blinn-Phong のスペキュラの様子です. m の値が増加してハイライトが集中するにつれて, スペキュラの明るさもきちんと増加しています.
- 最後に, 正規化係数についてはスペキュラの計算式を半球積分して求めた値の逆数を取ることで求めることができると思います.
- よく ディフューズのランバートやマイクロファセットでも正規化係数が出てきますが, 基本的には同じ方法で求められると思います.
参考文献
- "Computer Graphics Lighting" University of Freiburg