結局、陰影処理を行うのは顔モデルの表面のポリゴン上のピクセルだけなので、そこで、ある点に入射した光が、その周辺に対してどのような拡散光となって帰ってくるのかを調べてみる。
これは、一本の光のビームを皮膚に対して垂直に照射したときに照射点から半径rではどんな色の光がどのくらいの明るさになっているかを求めて計測する。この結果を特に「反射率拡散プロファイル」(RDP:Reflectance Diffusion Profile)と呼ぶ。
実際の計測の様子。全方位に同じ結果が得られると仮定しているため計測器は一次元(線分)状センサとなっている。「Analysis of Human Faces using a Measurement-Based Skin Reflectance Model」(Tim Weyrich,SIGGRAPH 2006)より |
下の図は「反射率拡散プロファイル」(RDP:Reflectance Diffusion Profile)をグラフ化したものだ。縦軸が反射率(出射光の輝度)、横軸が光を照射した位置からの距離を表す。つまり遠くに行けば行くほど赤が強く残ることを意味している。ここでは特に光の赤R,青B,緑Gで半径距離と反射率との関係が全く異なっているという点について注目しておきたい。
フィルタ径の異なる複数回のガウスブラーの結果で複数層による光散乱を近似実装
全ての表皮上のピクセルがこのRDPに従って皮下散乱して帰ってくると仮定してやれば、複雑な皮下散乱をこれで簡易実装できるのではないか。
しかし、この理屈がうまく行くのは、その表皮面ピクセルに対して垂直に光を照射したときだけだ。しかし、もし、この条件が使えるならば、皮下散乱は全表皮ピクセルに対して、このRDPに従ったボカしを実行すればいい。
表皮面に対しての垂直に入っていく光というのは、厳密には求められないが、それでもほとんどは脂質層を抜けてきた拡散光のことということができる。これはつまり、拡散反射の陰影処理を行って普通に画像テクスチャマッピングをした結果と仮定できる。
そしてRDPに従ったボカしは、各顔面上のピクセルに対して均等に行う必要がある。このボカしを実行するためには、ちょっと変わったプロセスをとる。
ピクセル陰影処理(実際のレンダリング)の計算はちゃんとした3D実空間で行うが、その出力(描き出し)は、その3Dモデルの皮を切り開いて2Dの紙に貼り付けたような座標系に対して行うのだ。立体を紙に転写するような……イメージ的には魚拓、あるいは地球の地図のような感じだ。
これを、今度は2D座標系(テクスチャ座標系)で、前出のRDPに従う形でボカしてやるのだ。これでまだ細かい問題は残るが表皮は皮下散乱した陰影結果へと近づく。
このままではただの魚拓画像なので、今度はこれを3Dモデルにちゃんとテクスチャマッピングし直してやる。これで皮下散乱したライティングの終了した顔モデルの完成となる。 ただし、ただぼかすだけは不十分で、そのブラーのさせ方には工夫が要る。
なぜならば前段で取りあげたRDPをもう一度見てもらうと分かるが、散乱の仕方が光のRGBの各成分によって異なるためだ。そのため、各ボカし半径ごとに、RGBの各成分が異なる減退率でボカし、それらを全て合成してやる必要があるのだ。
NVIDIAの実装ではボカし処理はガウスボカし(ガウスフィルタ)を採用し、ガウスフィルタの特性を活用して左右と上下に2回に分けて実行する方法を採用している。さらに、そのブラーの際には各RGBごとに重みを付けて、なおかつブラーの半径を変えて、合計6回行っている。これが前回の「複数層」の概念の再現に相当するわけだ。
テクスチャ座標系でのブラーの概念図。ガウスぼかし(ガウスフィルタ)は左右と上下に2回に分けて実装できるのが特徴で、GPU向きの処理といえる(ここの映像の結果はあくまで概念説明のための例で、実際のブラーの結果とは違う) |
異なるブラー半径ごとに異なるRGBごとの重みをつけてガウブラーを6回行っている。この表は前出のRDPに従うように生成されたガウスフィルタのフィルタ径ごとのRGB重み係数。上段が中心部に相当し、下段にいくほど外周。外周ほど赤成分が強く残る前出のRDPがこの表からも確認できる |
皮下散乱ブラーによって生成された複数のブラー結果はリニア合成される。この合成結果が皮下散乱成分であり、これもう一度3Dモデルに対して、最初に求めた脂質層での反射の結果(KS BRDF+フレネル反射)と一緒にテクスチャマッピングを適用すれば完成となる。(続く)
(トライゼット西川善司)