~下の画像をクリックすると、サテンのBRDFでライトが回った時のアニメーションが見られます。ラッカー”という言葉を見つけました。Repositoryを見つけました。データが公開されているもので、この論文はBRDFを2次元テクスチャで表現できる形に分解しようというものです。あるデータを使うと、下のようなライティングが32x32の2枚のテクスチャを差し替えるだけでエナメルのような光沢から金属光沢、布地の光沢まで実現することができます。'Satin'今回のプログラムは、次のものです。「z」,「x」で、ズームを切り替えます。カーソルキーでティーポットが動きます。「SHIFT」+カーソルキーでライトが動きます。シェーダは1_1で作っていますが、2_0にするとちょっと変わります。いつものように適当にファイルが入っています。出力されるフレームワークのファイルは紹介を省かせていただきます。アプリケーションのソースあと、実行ファイル、プロジェクトファイルが入っています。BRDFそもそも、BRDFとは何かということですが、BRDFとは物質の質感をあらわすパラメータで、物質に光が入射してきたときに、どのように反射するのか記述したものです。dωiとかける量です。ランバート拡散光の場合はBRDFは定数になります。BRDFは、「時間が進んでも戻っても物理法則は変化しない」という物理学的な信念から次の性質を持たなくてはなりません(ヘルムホルツの相反定理)。McCoolらは、このBRDFが多くの場合にいくつかの変数と法線ベクトルの内積の関数として書けることに気がつきました。H=normalize(ωo+ωi)や入射ベクトルと法線ベクトルの内積で書くことができます。P(ωi.N)が考え出されています。先ほど述べた入射ベクトルと反射ベクトルの相反性から、入射ベクトルと反射ベクトルに関する関数Pは同じものでなくてはなりません。PやQがBRDFを特徴付ける関数です。BRDF」と呼びます。ちなみに、今回のプログラムで表現されているものは、ほぼ全てこの3つの分解ですが、一般的には、この分解方法に縛られません。Maps)さて、因数分解されたBRDFを使う方法としては、テクスチャに格納してサンプリングする方法が良く知られています。鏡面反射が実現できます。0.5ところが、この方法では、各頂点のH.N以上に大きな値にはならないので、グーローシェーディングのようになってしまい、フォンシェーディングのようにはなりません。したがって、ハイライトが出にくくなります。一次元のテクスチャ今回は、2次元のテクスチャを用意し、H.Nの値が1の時にテクスチャの中心を指定し、値が小さくなるに連れて外側の値を指定するサンプリング法を採用します。今回の方法この方法なら、ポリゴンの割り方が大雑把で、各頂点での色の強さがハイライトの強さよりも大幅に小さくても、ハイライトが現れます。肝心のテクスチャ座標の指定方法ですが、接ベクトルを使います。接ベクトルTと従法線ベクトルBを使えば、メッシュ表面でのハーフベクトルなどの法線ベクトルとのずれの角度がわかるので、その値をテクスチャ座標に使います。0のときにテクスチャの中心を指すように調整する変数です。ここで、半径の値が問題です。McCoolらは、次の計算方法を提唱しました。2(1+H.N)この変換の式に対して、H.Nを変数としたテクスチャ座標に関する中心からの距離をグラフを描くと次のようになります。ここで、グラフが反比例のような形ではなくて、2次曲線的にひねくれているのには理由があります。H.NとH.B及びH.Tの値は独立ではありません。(H.T)2の関係が成り立ちます。(1+H.N)1/2でした。この関数は、H.Nが1のときに0で、H.Nが-1の時に無限大に発散します。この関数は、(-1,1)の範囲で単調減少関数なので、内積の値と距離は1対1に対応します。0.5になるのは-0.13付近で、テクスチャを使ってBRDFを表現するときには、内積の値が-0.13よりも小さな範囲は、この変換では正確には表現できません(まぁ、裏側だからあまり気にするな!)。ちなみに、今回の変換は、BRDFの値が接ベクトルや従法線ベクトルに依存するようにできるので、中心対称でないのテクスチャを使えば異方性のBRDFにすぐに移行できます。ライトベクトル、ハーフベクトル用のテクスチャ共に中心対称ではない異方性の反射になっています。■テクスチャの意味これで、どのようにやっているかはわかりましたが、実際にどのようにテクスチャを用意すればよいかはわかりません。SIGGRAPHとかでは、実際に測定してみてBRDFを決定するのが流行ですが、そこをはずれたNPRの世界では自分でテクスチャを描く必要があります。テクスチャがどのように構成されているのか探ってみましょう。Paint」を考えて見ます。このBRDFは、下のように、定数の色と視線ベクトルV、ライトベクトルLとハーフベクトルHからテクスチャをサンプリングして合成しています。ここで、Qは、それぞれのベクトルを放物変換で2次元のテクスチャ座標へ変換する関数で、pとqは、テクスチャを使ったサンプリングを意味します。Hの項がわかりやすいでしょうか。この項は主にPhongの鏡面反射成分をあらわします。中心が1で、後は急激に値が小さくなるので、HとNがほぼ一致するときだけ明るくなる鏡面反射の光だということがわかります。この項に関してテクスチャの中心を指すということは、ポリゴンを正面から見ていることをさします。ポリゴンを横から見るにしたがって、テクスチャの外側を指すようになるので、この項は見る(ライトの照らす)傾きを表現しているのだと理解でします。見る傾きによって変わる効果とは何でしょうか?それはフレネル効果です。正面から見たときには、それほど反射しませんが、ほぼ横から見たときには、全反射となってライトの光は強く反射されます。フレネル効果からおきる有名な現象に「カラーシフト」があります。横からの光の反射では、全反射になってしまうので、物体に塗られた塗料の色は反映されずに、光の色がそのまま反射されます。pのテクスチャはこの現象を再現していて、テクスチャの中心をさす正面を向いているときには、物体の色が乗りますが、横から見たときには塗料の色は乗らず、真っ白な色として入射光をそのまま跳ね返します。わかるのはこのくらいなのですが、何らかの参考になったでしょうか?■プログラムということで、今回のプログラムを紹介してきましょう。今回は、ピクセルシェーダ、頂点シェーダ共に1_1で可能です。今回の方法は、頂点シェーダでライトベクトル、視線ベクトル及びハーフベクトルからテクスチャ座標を計算して、ピクセルシェーダでそれらテクスチャ座標からBRDFを計算して色として出力します。頂点シェーダからピクセルシェーダに受け渡すデータは、3つのテクスチャ座標になります。};頂点シェーダでは、いつものように座標変換すると共に、法線ベクトルN、従法線ベクトルB、接ベクトルTを使って、視線ベクトルV、ライトベクトルW、ハーフベクトルHを2次元のテクスチャ座標に変換します。従法線ベクトルBと接ベクトルTは、データとして持つのではなく、ローカル座標のy軸方向から頂点ごとに計算してみました。この方法は、法線ベクトルがy軸を向いていると正しく動かないので、その点は注意しましょう。}テクスチャ座標の変換は、放物変換の公式どおりに座標変換をします。今回のプログラムでは、内積の値が-1の時に発散しないように、0.000000001をつけてエラーが起きないようにしています(でもこれ、固定小数点の計算だと0にまるまるね)。}ピクセルシェーダでは、テクスチャ座標からサンプリングして全てを掛け合わせます。}ちなみに、テクスチャはバイリニアサンプリングとはみ出したときのクランプ設定を必ずしましょう。ポイントサンプリングを適応すると、テクセルの形が無残にもみえてしまいますし、はみだしたときにループしているとライトの裏面などにおかしな表示がされてしまいます。};アプリケーションプログラムはそんなに複雑なことはしていません。適当に変数とテクスチャを設定して描画します。}■最後にps_1_1でできるので、Xboxのタイトルでは使われてるんですかねぇ。放物変換は、トゥーンなどの他の方法にも応用できるので、これから頻繁に使われていくでしょう。光源と正反対の位置に特異点(と言えばいいのかな?)ができちゃいません?というお言葉をいただきました。下の絵のティーポットの右側少し上の部分に奇妙な点が発生しています。今までのプログラムでは、テクスチャが-1から1に切り替わる部分で、途中の補間に「0」の部分を通るので、たとえばライトが裏側に行った部分で、変な点が出ていました。このままだと汚いので、修正しましょう。修正したプログラムは、次のものです。修正版:DirectX9(ピクセルシェーダ1.1)変更点はエフェクトファイルだけです。シェーダの入ったエフェクトファイル変更の考え方は、「裏面に光源が行ったときにおかしくなるのだから、その時の強さを0にしてしまえ」ということです。外側が必ず黒いわけではないので危険ですが、裏に行ったときには、陰になるので問題ないでしょうという感じです。プログラム的な変更は、頂点シェーダからの出力に「裏への隠れ度」であるIntensityを追加して、普段は1、裏になった時は0になるようにプログラムで調整します。構造体は、具体的には次のように変更します。};ピクセルシェーダでは、その色の強さを乗算して影響させます。}実際のIntensityの計算ですが、放物変換の座標変換でアルファ成分に値を設定しておいて、Intensityに出力します。Intensityには、全てのベクトルによる陰の影響度を入れるのではなく、ライトベクトルの影響だけを反映させました。実際問題、H.Nが負になることはないですし、V.Nが負になるのは面が裏を向いている時で、境界でしか影響は起きないのでほとんど効果は入りません。したがって、L.Nだけを考えれば良いということになります。}実際の強さの計算ですが、0と1をいきなり切り替えると、テクスチャのサイズの小ささによるぎざぎざが目立ってしまったので、適当な場所で線形補間しています。線形補間するのは、ちょうどテクスチャの横の端から対角の端の間までにしました。この量はいいかげんなので、好きなように調整したり、マイクロファセットを導入して、その幾何減衰率を採用したりすることも可能でしょう(ここは1次元テクスチャで問題ないはずですし)。ぎざぎざプログラムが汚くて申し訳ないのですが、強さの計算の部分は、次のようになります。}この変更で、先ほどの点は綺麗に消えます。なくなってしまうので、許される変更かどうかはなんともかんとも...もどるimagire@gmail.com。