いざSSS・後編
2012年03月29日(Thu)
というわけで前回の続き。
3. Scatterノードの役割
それでは一番使用頻度が高(くなるかもしれな)いScatterノードについて見ていこう。Scatterノードは代替拡散に接続する。間に他のノードを挟むのはいいけど、ルートノードの他のパラメータに接続すると計算結果が反映されないので注意しよう。プリセットのMaterialは、ここではSkin 1を選択している。Use_Material_Colorはプリセットの色を拡散色に使用するので、テクスチャを使用する場合はこのチェックを外すべし。
とりあえずテスト形状。他の値はすべて0にしておく。

SSSを試そうとして、いきなり人物フィギュアの複雑なツリーに組み込んで、長時間レンダした挙句「効果がよくわからなーい」とか言ったことがある人は反省しよう。なんでまだ効果すらよく分かってないものに対して、そんな効率の悪い方法で時間を掛けられるのかと。

レンダリングオプションのSubsurface Scatteringにチェックを入れると、シャドウマップとIDLの計算後、レンダリング前にSSSノードが存在するマテリアルグループだけの計算が入る。まず表面下つまり物質内部をレンダリングして、その結果を元に本レンダリング時は表面の状態がどう変化するかを計算するのだ。

Scatterノードを適用した方は、立方体の角の部分を越えて光が側面に滲み出しているのがわかる。側面は光の当たる側が明るくなっているのに対して、正面は逆に角の周辺がわずかに暗くなっている。正面から入射した光が内部で散乱し、正面ではなく側面へ脱出してしまったためだ。

側面(暗部)に現れる散乱光の色と量はプリセットによって異なる。Custom Scatterノードの場合は、Scatter Colorで指定することができる。

図を見れば、側面(暗部)に現れる色と正面(明部)周辺で暗くなる色は、補色の関係にあることがわかる。出ていった光の成分だけ暗くなるのだから、当然といえば当然だろう。ということは、私たちが普段見ている肌の色は拡散色と散乱色が合わさったもので、実際の肌の色(表面色)は図の周辺部分のようにもっと青白いことになる。
Texture_Detailでは、表面色と内部色の比率を決定する。値が0のとき、Colorに接続された情報はすべて物質内部の色として扱われる。逆に1の場合、物質内部は白色で計算され、Colorに接続した色で計算された拡散光と乗算される。

0の方は中に色が練り込まれているように見える。1の方はプリントされた柄っぽいかな。
内部散乱で決定した色は、表面に出てくる時に表面の拡散色と乗算される。ScatterノードではTexture_Detailが1の時、ちょうど接続されたColorの色を再現するように設計されている。そのためTexture_Detailが1未満の場合、中間色がColorの色よりも若干白っぽくなるので注意しよう。
さて、プリセットの一覧を見ると、散乱色の他にもにじみの幅がそれぞれ異なっていることがわかるだろう。Scatterノードでは、プリセットの材質に応じて散乱光の現れる距離も固定されている。通常のシーンでちょうど物理的に正しいにじみ幅になるように設定されているのだ。
しかし、シーンによってはオブジェクトを拡大縮小して使用する場合もある。例えば小人の世界を作る時、シーンの作りやすさを考えれば、人物フィギュアを縮小するより小道具を拡大した方が扱いやすい。しかしそのままでは、小道具の表面下散乱は拡大された後の寸法を元に計算されてしまう。これでは人物フィギュアが小さくなったようには見えない。

このような場合に使用するのがScaleパラメータだ。小道具を二倍に拡大して1/2サイズの小人の世界を作るなら、ScatterノードのScaleを0.5にする。すると散乱光の現れる距離がそれまでの倍になる。逆に巨人の世界(小道具を50%に縮小)の場合はScaleを2.0にすると、散乱光の距離が半分になる。これによって拡大縮小されたシーンでも物理的に正しい距離で計算することができる。

オブジェクトを拡大縮小しない場合、Scaleは単なるにじみ幅のパラメータと同じになる。プリセットのにじみ幅が気に入らない場合、このパラメータを調節することになるだろう。

MaxErrorは散乱光を描画する時の品質を決定する。値が小さいほど精度が高く、速度が落ちる。値か大きければ精度は落ちるが速度は向上する。具体的にはSSSの計算時間ではなく、レンダリング時の時間が伸びる。特に問題なければ初期値のままでいいだろう。
4.人肌のSSSシェーダ
さて、お待ちかねの実践編。といっても、既にSSSを取り入れて試行錯誤している人にはあまり役に立たないだろう。より複雑なシェーダツリーを構築することがテクニックなら、私がやっていることは初級を通り越して初心者レベルだからだ(毒)。
というわけでM4をロード。標準マテリアル(マテリアルコレクションファイル)を当てている。

シェーダツリーはこんな感じ。使ってないところは暗くしている。確かV4はもうちょっと複雑だったような気が……。

頑張ってるけどP7以前ってカンジの構造だ。環境色に赤を入れ、暗い部分が赤く浮くようになっている。その分通常の拡散色に青を乗算して、明るい部分の赤色が飽和しないようにしているらしい。明るいシーンではそこそこまともに見えるものの、真っ暗な状況で赤黒い人影が現れるという、正直「使えない」構成だ。これ系のマテリアルが流行ったおかげで、キャラアイテムのMATは当てたらまず全見直しという習慣が通常ルーチンとなった(あ、前からか)。
ちなみに誤解してる人がいるかもしれないけど、私が「加算系のノード」という造語で呼んでいるのは、単なる環境色や代替拡散というわけではない。加算に対しては乗算があるわけで、何に対して乗算かというと、ライトの強度である。ライトの強度が乗算されない=真っ暗な時に真っ黒になっていない=一定の値を底上げ(加算)しているノードのことを加算系と呼んでいる。なので代替拡散に繋がれているノードも、ちゃんと陰影付けされるノードは加算とは呼ばない。マップや固定の値を単純に引っ張っていて、真っ暗闇でも描画されるのが加算系である。
何はともあれ、いらないものをばっさりと落としてみる。

すっきりした。拡散色は白に、環境値は0にしておこう。

あんまり見栄えが変わらないね。今までのはなんだったんだろうね(笑)。
ではここで、代替拡散にScatterノードを接続する。Scatterノードは拡散成分を計算するものなので、通常の拡散値は0にしておく。で、テクスチャをScatterノードのColorに接続。ルートノードの拡散色に繋いでる見本なんかもあるけど、自分はテクスチャシェーディングは使わないので(いちいちマップの再読み込み入って重くなるだけだし)、特に接続はしていない。鏡面は少しだけ青みがかった明るい灰色にして、元のマップとテクスチャから適当に適当にこしらえたのものを接続。ちゃんとしたスペキュラマップがあるならそれを使えばいい。

で、レンダするとこんな感じ。目のマテリアルにも手を入れた。

せっかくなので新ノードのKs_Microfacetを代替鏡面に接続。代わりに通常の鏡面値は0にする。

で、レンダ。

SSSの効果が少しキツいなー、と思ったときはScaleを少し大きくするといい。

こんな感じかな。Ks_Microfacetの粗さを制御するマップがあれば、スペキュラももう少し見栄えがよくなると思う。たぶんblinnノードにあれこれ繋いで調整するより効果的なんじゃないかな。
果たして。
SSSで必要なことはこれだけである。何か難しいことがあっただろうか?
SSSの計算にかかる時間は、SSSを使わないときの時間に関係する。SSSを使わないときに時間がかかるなら、SSSの時間もかかるのだ。合計すればよりレンダ時間が増大することになる。マテリアルの調整でテストレンダを繰り返す時は、どうしても必須でない限りレイトレースやIDLなどは使わない方がいい。
Texture_DetailやScaleを部分的に調整したくなったら、マップを作ることになるだろう。自分で描き起こしてもいいし、既存のマップに演算ノードを繋いで作ってもいい。どこをどう調整したいかが頭の中にはっきり浮かんでいれば、無駄にノードを重ねる必要はない。本当に必要なノードだけを追加することができるはずだ。中には「本来、拡散反射と鏡面反射の区別はない」という部分を忠実に再現するため、両者を合成して代替拡散に繋いでいる強者な人もいる。何をどう取捨選択するかは個人の自由である。できるなら無駄なく効果的に、なおかつ思想の感じられるマテリアルを組みたいものである。
5. おまけ(Ks_Microfacetノード)
リクエストがあったので、Ks_Microfacetの値の変化の図。パラメータは粗さと強度しかないのでどれぐらいの値でどれぐらいのハイライトが出るのか把握しておけばいいだろう。

中央付近と周辺部のハイライトの現れ方の違いに注目。

つやつやな物体とさらさらな物体がこれ一つでカバーできる。応用範囲は広いと思う。

以上。さー世界だー(何)