正規化Half-Lambert


 1.はじめに…
Half-Lambertも正規化してみました。Half-Lambert自体は物理則的に正しいものではないないですが,…一応ね。





 2.Half-Lambertのおさらい
Half-LambertライティングはValve社が開発した,柔らかく見せる表現手法です。
通常のLambertライティングの場合は,余弦(cos)を用いるため-1.0fから1.0の範囲のカーブとなります。
-1.0fから1.0の値の範囲なので,0以下の部分は黒く表現されてしまいます,そこでValve社では,急減に変換するコサインカーブルをゆる~くして,マイナス部分が出ないように工夫をしたLambertライティングを行っています。 具体的には,コサインのカーブが半分になるように,1/2を乗算し,この結果に1/2を足しこみ持ち上げて,その結果を2乗するという方法を使っています。

Jason Mitchell. February 2008. "Stylization With a Purpose: The Illustrative World of Team Fortress 2." Game Developers Conference. より引用

コードにすると下記のような感じになります。
float diffuseLight = max(dot(L, N), 0) * 0.5 + 0.5;
float3 diffuse = Kd * lightColor * (diffuseLight * diffuseLight);


 3.正規化Half-Lambert
さて,Half-Lambertは物理的な法則に全く沿っていないわけですが,一応エネルギーの保存について考えていきます。
Half-Lambertはcosの値を0.5倍して0.5fを足して,2乗するので下記のようになります。

まず,そもそもHalf-Lambertは物理則に沿っていないのですが,Lambertを変形させて作っているので,Lambertからの相対値として考えてみます。
Lambertからの相対値とみなしますので,cosθで割った下記が定義となります。

この定義について,少し考えてみます。
まず半球積分するので,式を直すと
のようになります。
θ/2だとわかりづらいので,置き換えしてみます。

式を直すと,

…となります。この直した式をまたゴリゴリ計算していきます。

従って,

ようやく,値が求まりました。
この求めたの逆数が正規化係数となるので3/4πをかけてあげれば,エネルギーが保存されるということになります。


 4.実装
実装コードは下記のようになります。ただ単純に正規化係数をかけるだけです。
00013:  //---------------------------------------------------------------------------------------
00014:  //! @brief      正規化ハーフランバートライティングを行います.
00015:  //!
00016:  //! @param [in]     diffuse     拡散反射色.
00017:  //! @param [in]     lightDir    ライトベクトル.
00018:  //! @param [in]     normal      法線ベクトル.
00019:  //! @return     ランバートライティングした結果を返却します.
00020:  //---------------------------------------------------------------------------------------
00021:  float3 NormalizedHalfLambert( float3 diffuse, float3 lightDir, float3 normal )
00022:  {
00023:     float val = max( dot( normal, lightDir ), 0.0f ) * 0.5f + 0.5f;
00024:     return diffuse * val * val * ( 3.0f / ( 4.0f * PI ) );
00025:  }


 Download
本ソースコードおよびプログラムはMIT Licenseに準じます。
プログラムの作成にはMicrosoft Visual Studio 2012 Express Editionを用いています。