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

コードにすると下記のような感じになります。
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πをかけてあげれば,エネルギーが保存されるということになります。
Half-Lambertはcosの値を0.5倍して0.5fを足して,2乗するので下記のようになります。

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を用いています。
プログラムの作成にはMicrosoft Visual Studio 2012 Express Editionを用いています。