[GDC07#29]CascadesとAdrianne,NVIDIA技術デモの秘密
■少ないポリゴンでリアルな水流を再現する「Cascades」
Cascadesの解説を行ったNVIDIAのRyan Geiss氏
 |
NVIDIAのセッションでは,GeForce 8シリーズ用のデモプログラムCascadesとAdrienneを中心とした技術解説が行われた。 Cascadesは,DirectX 10(というか,それに相当するOpenGL)を使用したプログラムである。Cascadesの特徴は,多くのものをプロシージャルに処理しているので,インタラクティブ性がきわめて高いということである。しかも,ほとんどがGPUによって処理されている。ジオメトリシェーダなどを駆使した実装となっているため,デモとしての見どころは多いプログラムだ。
●地形の生成 Cascadesの地形は,3次元テクスチャで生成されている。96×96×256個の空間に描かれた濃淡をもとにして岩の部分と空間を表現している。この3次元テクスチャは,水を流す際の衝突判定にも用いられている。 造形に関しては,崖,岩棚,捻り,ノイズといった観点でそれぞれに工夫がなされているようだが,あまり細かい部分を見てもしかたがないので,見て「なるほどねえ」と納得したノイズの話を。ノイズは,複数の周波数帯に分けて加算されている。低い周波数帯のノイズで大まかな形を作り,そこに高い周波数帯のノイズで微細な造形を加えていくのである。パラメータ次第で,地形の複雑度は自在に変えられるのである。
●均一なシェーディング 3DCGの経験がある人ならお分かりだろうが,テクスチャマッピングにはいくつかのモードがあるものの,それぞれ一長一短である。1軸からの平面マッピングではほかの軸方向で間延びし,軸に対する円筒マッピングでは軸方向から見るとおかしくなり,球状のマッピングでは極部分が稠密になる。全体に均等なマッピングを行うことは難しいのだ。 Cascadesでは,Tri-Planar Texturingといわれる方法で,3方向からの平面マッピングを併用することによって,可能な限り全体に均一なマッピングを実現している。これは多くのゲームで参考になる実装ではないだろうか。
上段左:空中に浮かんだ岩の作成手順
上段中:崖と岩棚の様子
上段右:螺旋状の回転を加える
中段左:周波数別のノイズの例
中段中:ノイズを加えていくと形状が複雑になる
中段右:凹凸と遮蔽部の処理を加える
下段左:1方向からのマッピングでは,横方向で歪みが出る
下段中:3軸方向からマッピングを行ったもの
下段右:それぞれの方向からのマッピングを色分けしてみた
 |
 |
 |
 |
 |
 |
 |
 |
 |
写真からフィルタ処理したハイトマップデータを使用している
 |
●水流 基本的にパーティクルで実装されている。恐ろしく細かいパーティクルだと感心していたものの,実際には予想よりはるかに大きなポリゴンで流れを実現していたことが分かった。 1枚の四角形ポリゴンには,256個のアニメーションするパーティクルが描かれている。なるほど,これならば流速の大きなところでは縦に引き伸ばされ,パーティクルにも自然にブラーが発生して流れを表現できる。それでいながら,制御が必要なパーティクル(ポリゴン)の数も抑えられるわけだ。 パーティクル自体も,吹き出し口,衝突で発生した霧,岩の上を滑って流れる水,落下中の水,落下途中で発生する霧という5種類が用意され,状況に応じて切り替えられている。
上段左:環境光を遮蔽しないとこのようになるが
上段中:窪み部分には外光が入らないようにするとこうなる
上段右:深い窪み部分も外光が遮蔽されたほうが自然になる
下段:詳細部分でのディスプレイスメントマッピングの例
 |
 |
 |
 |
 |
 |
水流の処理
 |
●濡れた岩 水が当たった部分は色が変わる。これは水のパーティクルが3Dテクスチャ(岩)に衝突したときに,岩の色を変えることで実現されている。実際には,岩の影の部分の色を使って,色を濃くするという処理だ。また,とくに説明はなかったが,水の流れが止まってしばらくすると,表面が乾いていく処理も実装されている。
上段左:場所によって使用するパーティクルを変えている
上段右:パーティクルの境目では両者をブレンドしてつないでいる
下段左:水の流れは,このような大きめのポリゴンで構成されている
下段右:ポリゴン上には256個の水滴(微細な運動をしている)が貼り付けれている
 |
 |
|
 |
 |
|
●トンボの群れ 空中に浮いた岩の周りを飛んでいるトンボの群れは,一種のパーティクルのような感じで実装されている。トンボは岩の部分を避けるようになっており,また,ある程度群れをなして飛ぶようになっている。
上段左:岩の周りにはトンボが飛び回っている
上段右:トンボはランダムな軌道で岩の周りを周回する
下段左:3Dテクスチャを参照して,岩にぶつからないように飛ぶ
下段右:拡大するとトンボはこんな感じ
 |
 |
|
 |
 |
|
■技法の積み重ねでリアルな肌を演出する「Adrianne」
Adrianneの解説を行ったNVIDIAのEugene d'Eon氏
 |
ご存じ実在モデルを使用したAdrianneのデモは,それなりに衝撃的でGeForce 8シリーズの底力を示すものとなっている。ただ,NaluやLunaと比べると,デモ自体は単純な構成であり,論点はもっぱら皮膚表現に絞られている。
基本的なシェーディングには,金属などに多用されるPhong Blinシェーディングではなく,物理的な特性によるBRDF(双方向反射率分布関数)を使ったものになっている。それにブラーを何重にもかけたものを合成しているのだ。まず,事前計算で,
・ディフューズカラー(基本的な色) ・スペキュラー(光沢部分の分布) ・バンプマップ ・遮蔽部分
を処理したものを用意する。光源の影響を受けないバンプやスペキュラーはよいのだが,遮蔽部分はちょっと微妙かもしれない。これは鼻の穴の中など,光が差し込まない部分が明るくなるのを防ぐためのものだが,事前計算で済ませているあたり,光源の移動などはあまり考慮されていないようだ。
上段左:前処理で遮蔽部分の輝度を指定する
上段中:ディフューズカラーの指定
上段右:バンプマップ
下段左:スぺキュラーの強度分布
下段中:光源から光を当てて輝度を計算
下段右:皮下散乱を計算して加える
 |
 |
 |
 |
 |
 |
●拡散光のぼかし 次に投射光と皮下散乱を加える。皮下散乱にはブラー(ぼかし)をかけているのだが,これは入射光が,皮膚内で拡散して出てくる様子を示している。結果的にブラーをかける処理と同等ということだ。まあ確かに,内部で乱反射して拡散して出てくる状態は,ガウスぼかしのような,濃度分布を持ったぼかし処理と似ているといってよいだろう。
上段:皮下散乱にブラーを加える
下段左:ブラーを重ねたものを合成する
下段中:反射時の表面散乱をシミュレート
下段右:PhongシェーディングとBRDFでの質感の違い
 |
 |
 |
 |
 |
 |
ただ,ガウスぼかしについては,1回ではなく最低でも2回以上のぼかしをかけることが推奨されている。人肌表現の研究では,多層構造を考慮したほうがリアルになるという結果が出ていて,その多層構造を表現するには,多段階のぼかし結果を用意しておいて,それを合成するという方法がとられている。
また,ぼかしは必ずテクスチャ空間で適用するという注意点も示された。2次元のテクスチャは,3次元のポリゴンモデルに回り込んで張られるので,テクスチャ画像自体には3D画像にない歪みが加わっている。これを考慮しておかないと不自然になるわけだ。
上段左:失敗例
上段中:失敗の原因を考えると皮膚内部での散乱が考慮されていなかった
上段右:肌を多層として考えたほうがリアルになるという研究事例
下段左:皮下散乱にガウスぼかしを1段使用したところ
下段中:さらに2段目のぼかしを入れたものを適用したところ
下段右:多段階のぼかしをブレンドしたもの
 |
 |
 |
 |
 |
 |
皮下散乱の考え方
 |
●RGB重み付け 皮膚での反射や拡散では,RGB成分に重み付けを加えた処理を行う。光の波長と透過性の問題や,血液の色などを考えると自然な処理といえるだろう。
●ガンマ補正 最終的な出力に「ディスプレイと特性が違うのでガンマ補正をしなければならない」ということなのだが,Cascadesの解説ではまったく触れられていなかった事項でもある。話を聞いた後でも,なんとなく場当たり的な対症療法に思えて,いま一つ釈然としない。
上段左:RGBの各要素に重み付けを行う
上段中:テクスチャは2次元平面では歪んだ形で記録されている
上段右:それを考慮してブラーをかける必要がある
下段左:6回のブラーを重ねたもの。カエルはBlinn-Phongシェーディングによるもの
下段中:エネルギー保存則を適用する
下段右:ガンマ補正をしないといけないらしい
 |
 |
 |
 |
 |
 |
●継ぎ目の解決 Naluなどでも継ぎ目を手や髪で隠れやすい位置でパーティショニングすることで目立たなくしていたものの,どうしても継ぎ目は残ってしまっていた。Adrianneでは,1枚のマッピングデータを使いながら,継ぎ目の問題を解決している。
●スペキュラーの多重合成 反射して光沢になる部分の処理だが,1回ではいけないとされている。これも多層構造の反映であろう。ぼかしのときと同様に多層での結果を合成する。
画像を比較してみても,いくつかの処理についてはどれくらい効果的なのか分からないが,いろいろな試行錯誤を重ねてデモが作成されていることはよく分かった。さてそれはそれとして,人肌の表現への基本的なアプローチは,これで確立されたのだろうか? まだ研究の余地はあるだろうし,Adrenneの処理はゲーム内で使うにはコストがかかりすぎるような気もする。せっかく公開されたノウハウなので,ゲームメーカーには,これを大いに参考にしてシェーダプログラムを書いてもらいたいものである。(aueki)
上段:継ぎ目のエッジ部分で余計な色が交じらないように気をつける
下段左:テクスチャの継ぎ目をどのようにしてなくしていくかが問題
下段中:光沢でも多層の処理を行う
下段右:微細部はバンプマッピングで表現
 |
 |
 |
 |
 |
 |
|
|
|