西川善司の3Dゲームファンのための「KILLZONE 2」グラフィックス講座(前編)
PS3のハイクオリティグラフィックスはDeferred Shadingでキマリ!?


「KILLZONE 2」

4月23日発売予定

価格:6,980円

CEROレーティング:D(17歳以上)


【著者近影】
 三度の飯より格闘ゲームが大好きなテクニカルジャーナリスト。本誌では主にGPUや3Dグラフィックス関連の記事を執筆している。生まれて初めて買ったゲームハードウェアが「ファンタジーゾーン」の中古ゲーム基板というほどのゲーセン小僧。ゲームをオールラウンドに愛するが、どちらかと言えばエキセントリックな内容のゲームを好む傾向にある。最近のお気に入りは「NINJA BLADE」(フロムソフトウェア)。個人ブログはこちら

 日本ではあまり知られていないが欧米では絶大な人気を誇る1人称シューティングゲーム(FPS:First Person Shooter)が「KILLZONE」シリーズだ。

 開発を担当したのはオランダ随一のハイテクスタジオGuerrilla Games。常に最新技術を自社タイトルに取り入れていく姿勢は、ゲームエンジンを手がけるEPIC GAMES、CRYTEKなどとよく似ており、最新作の「KILLZONE 2」は魅力的なゲーム内容はもちろんのこと、PS3向け最新鋭技術のショーケースとなっている。

 「KILLZONE 2」は、欧米では2月に発売され、掛け値なしの高評価を受けた。日本でもいよいよ4月23日にSCEJからの発売が予定されている。まさに発売直前という絶好のタイミングというわけで、今回は先月サンフランシスコで開催されたGDCでの技術セッションの内容をベースに「KILLZONE 2」のグラフィックステクニックをじっくりと前後編で紹介していきたい。



■ 「KILLZONE 2」が採用したDeferred Shadingパイプラインとは?(1)
~シェーダーヘビー・グラフィックスの最適化手段の1つ

GDCで「KILLZONE 2」に関するセッションを行なったGuerrilla Games Senior Programmer Michal Valient氏
左上がデプスバッファの内容。右上がピクセル単位の法線ベクトル。左下がテクスチャカラー、右下がスペキュラ。こうした中間値を先にレンダリングして最終的なライティングを後回しにして行なうのがDeferred Shading

 一般的な3Dゲームグラフィックスは、頂点処理→ピクセル単位の陰影処理という流れでレンダリングを行なう。このアプローチにあえて名前を付ければ「前方(順方向)レンダリング(Forward Rendering)」と呼ばれる。

 この前方レンダリングにおいて、オブジェクトごとにシェーダーセットを切り換えたりする描画エンジンでは、ピクセルシェーダーを動かして得た結果が深度テストで描き出されずに捨てられてしまうことも多い。これは無駄な演算ということになる。

 また、マルチパスレンダリングでは何度も同じジオメトリで構成されたシーンをレンダリングするようなケースも出てくる(ジオメトリ処理の無意味な重複)。つまり、前方レンダリング法では、画面に表示するフレーム内の総ピクセル数よりも多く演算してその結果を捨てたり、反復的に同じ計算を無駄に行なってしまうようなことがしばしばあるのだ。

 また、ひとつのシーンのレンダリングに高度なピクセルシェーダープログラムを複数動作させる場合、それぞれのピクセルシェーダープログラムが同じ計算中間値を使用することがしばしばある。それが複雑な計算やテクスチャ参照を伴うものだった場合、その中間値を求めるだけでGPUに負荷がかかってしまう。

 そこで、複雑な陰影処理を行なうヘビー・シェーダーが多用される3Dグラフィックスのレンダリングには、既存の「前方レンダリング」ではない別のアプローチの模索が始まった。その実践的な方法として最近台頭してきたのがDeferred Shading(ディファードシェーディング:遅延シェーディング)という考え方だ。

 Deferred Shadingでは、シーン内のポリゴンベース(ジオメトリベース)のレンダリングを、重い材質表現ピクセルシェーダーは動かさずに先に行なってしまい、複数のピクセルシェーダプログラムで必要となるような計算中間値を複数のバッファに先に同時出力してしまう。その際に有効となるのがDirectX 9以降で有効に活用できるようになったMRT(Multi-Render-Target)だ。一度のレンダリングパスで複数バッファに異なる値を同時出力する機能であり、DirectX 9では4枚、DirectX 10では8枚の同時出力が可能となっている。

 このMRTを使って複数のバッファ(テクスチャ)に対して出力する内容は、描画エンジンごとに異なるが、深度(Z)値、ポリゴンを構成するピクセル単位の法線ベクトル情報、スペキュラ値、アルベド(テクスチャを適用した結果)などがある。MRTを使えば、これらのデータを一度に複数のバッファに書き込むことができる。

 そして、最終的なピクセル単位のライティングは、その先出ししたその中間値を使って画面座標系でポストプロセス的に行なう。ピクセル単位の陰影処理をあとから行なうので「Deferred(遅らせた)Shading」という名前が付けられた。ちなみに、もともとの考案者はMichael Deering氏で、このアルゴリズムを実に20年前の「SIGGRAPH 1988」にて発表している。

 ファーストパーティー扱いのキラータイトルとしてPS3最高位のグラフィックスを求められた「KILLZONE 2」では、シェーダ・ヘビーとなることが確実視されたため、レンダリングパイプラインとして、このDeferred Shadingの採用を決めたわけである。

【Deferred Shadingの処理プロセス】
深度値(Z値、デプス値)カメラ座標系の法線ベクトル情報
鏡面反射強度ハイライト強度
動きベクトルテクスチャカラー
Deferred Shading完了後ポストプロセス適用後の完成画面



■ 「KILLZONE 2」が採用したDeferred Shadingパイプラインとは?(2)
実装とジオメトリ・パス

「KILLZONE 2」のDeferred Shadingの4MRTの内訳。Deferred Shadingにおける、この複数の中間値格納バッファはまとめて「G-Buffer」と呼ばれる

 「KILLZONE 2」におけるDeferred Shadingは、大まかなステップとして、

    (1)ジオメトリ・パス(Gバッファ作成フェーズ)
    (2)ライティング・パス(ピクセル・シェーディング)

の2ステップを踏む。最初のジオメトリ・パスでは、シーン内の全ポリゴンを普通にレンダリングするが、重いピクセルシェーダーによるライティングは行なわない。

 PS3のGPUのRSXはNVIDIA GeForce 7800 GTXデチューン版であり、DirectX 9世代のGPUということになるため、MRTは4つまでとなる。「KILLZONE 2」のDeferred Shadingのジオメトリ・パスでは、この4MRTで図のようなRT0~3までの4枚の出力を行なっている。

 まず、MRTに用いる出力フォーマットだが、PS3のRSXではFP16-64ビットバッファはバスの性能的に能力不足なので必然的に整数32ビットバッファ(RGBA8)が選択されたとのことだ。

 次にレンダリング解像度は1,280×720ドットを採択。アンチエイリアスはNVIDIAのQuincunx 2×MSAAモードを適用したので、1,280×720×(RGBA8×4枚+D24S8)×2×MSAAで合計36.8MBの帯域消費を見積もることができたため、開発チームとしては「まあ、これならば」ということで決定したようだ。なお、4MRTで出力された各中間値バッファは後述のポストプロセスなどで、低解像度版に変換された再利用される。

 それでは4MRTで出力された各バッファ(G-バッファ)の内容を順番に見ていくとしよう。

 デプス(深度)/ステンシルバッファは、そのシーンの完成後の深度値が格納される。後段のライティング計算でカメラ座標系の位置情報が必要になったときは、この深度値から逆算して求めることになる。

 RT0のLighting Accumulation Buffer(LAB)は、入射光情報を記録しておくバッファとなり、後段のピクセルライティングを行なう際にも用いられる。最初のジオメトリ・パスでは、LABには、ライトマップや、後で解説するLight Probeを使った疑似大局照明の結果、環境光などを適用した結果が出力される。LABのα部分にはHDR輝度値が格納されており、その輝度レンジは0.0~2.0。「KILLZONE 2」のHDRレンダリングは整数32ビットバッファを使った疑似HDRレンダリングになっている。

 RT1はジオメトリ・パスにて、各ピクセルにおけるカメラ座標系の法線ベクトルのx、yが格納される。法線マップの適用結果などもここに格納される。法線ベクトルは正規化されているため(絶対値=1)逆算が可能ということでzは格納されない。具体的には「z=√(1-x^2-y^2)」で求められる(zの符号は常に正(+)になるが実害はない)。

 法線ベクトルのx、yは16ビット浮動小数点(FP16)として格納するが、その際に、FP16×2を32ビット整数バッファに格納するNVIDIA系GPUの特有命令であるunpack_4ubyte命令を利用している。

 RT2のRとGにはジオメトリ・パスにて、画面座標系の動きベクトル(Motion Vector)が格納される。このRT2の活用については後編のモーションブラーのところで触れる。RT2のBとαにはスペキュラにまつわるパラメータが入る。Bにはどのくらいの強度のハイライトを出すのかを表した係数値を対数値「log2(n)/10.5」として格納される(Specular Power)。αにはどのくらいの鏡面反射を行なうのかの強さを表すスペキュラ強度値(Specular Intensity)が格納される。

 RT3のRGBにはオブジェクトに適用されたテクスチャカラーが格納される。RT3のαはこれは事前計算された平行光源(太陽光)からの静的な影のレンダリング結果が格納される。

【Lighting Accumulation Buffer】
ジオメトリ・パスを終えたばかりのLighting Accumulation Buffer。実質的には静的なライティングが行なわれたのみの状態。テスト画面のためテクスチャはあえて適用無しライティング・パスを終えたばかりのLighting Accumulation Buffer。動的なライティングまでが行なわれたのみの状態。テスト画面のためテクスチャはあえて適用無し。陰影の違いや影の有無に注目



■ 「KILLZONE 2」が採用したDeferred Shadingパイプラインとは?(3)~ライティング・パス

Deferred Shadingのライティング・パスは、処理的な視点から表現すると、「光源をレンダリングする」というイメージになる

 ライティング・パスでは1フレームあたり100以上の(場合によっては300以上も)動的光源からのライティング、10個以上の影生成を伴う動的光源からのライティングを伴うため、非常に重いフェーズになる。

 前方レンダリングでは3Dオブジェクト基準で、「3Dオブジェクトにどんな光が当たっているか」という概念でライティングを行なうが、Deferred Shadingでは既にできあがっている2.5D的な映像に対して、画像処理的なポストプロセスとして光源をレンダリングする。たとえば、300個の光源があれば300回の画面のポストプロセスを行なうことになる。

 概念的な話をすると、ジオメトリパスで描き上げた立体的な無着色な箱庭に対して次々に光を当てて色づけていくような工程になる。無数の光源がシーン内の3D空間に配置されていても、その光源の全てが何かを照らしているわけではない。前方レンダリングで、「見えないオブジェクトを描かない」という最適化手法があるように、Deferred Shadingでは影響を与えない光源はスキップするという最適化を行なう。

 また、影響を与える光源であっても画面内のどのピクセルを照らすかどうかのテストを行なって、影響のあるピクセルについてだけライティング演算を行なう。点光源はその影響範囲が球状となるので、光の届く範囲の球体を、ジオメトリ・パス後で生成済みのシーンの深度(Z)値を吟味しながら、別の深度(Z)バッファにレンダリングする。

 影生成でステンシルシャドウボリューム技法というのがあったが、あれと似たような発想で、光領域(Light Volume)をレンダリングするのだ。レンダリングしたLight Volumeを用いることで、画面内のどのピクセルがその光源の影響下なのかが判定できるので、あとは希望のライティング計算をするだけだ。

【ライティング・パス】
視点から見てLight Volumeの後面よりも前にあるピクセルをマーク視点から見てLight Volumeの前面よりも後側にあるピクセルがライティング対象になると判定



■ 「KILLZONE 2」が採用したDeferred Shadingパイプラインとは?(4)
~太陽光(平行光源)ライティングにまつわる特例処理と影生成

 動的光源は前述のLight Volumeの考え方でライティングするが、問題となるのは全域に降り注ぐ平行光源(太陽光)だ。平行光源が動かなくても、動的キャラクタは動くので、向きを変えたり姿勢を変えたりすれば陰影は変わる。よってライティング・パスでのライティングは必要不可欠だ。

 しかし、いってみれば太陽光は全域に降り注ぐのでいってみれば画面全体がLight Volume内に入るのと同じだ。そこで、開発チームはユニークな最適術を適用している。それは、ジオメトリ・パスで生成したRT3の太陽光からの静的な影の情報だ。このRT3にある影の部分は太陽光が当たっていないと仮定できるので、太陽光のライティング範囲外とみなし、ライティング・パスでスキップしてしまうのだ。

【太陽光(平行光源)ライティング】
ジオメトリ・パス後にRT3に格納された静的な影つまりその部分は太陽光からのライティング適用範囲外とみなせる(赤くマークした部分)完成画面

「KILLZONE 2」の影生成はデプスシャドウ技法と静的な影のハイブリッド表現からなっている
カスケードされた4枚のシャドウマップを色分けして可視化したテストショット

 「KILLZONE 2」における影生成は、RT3にジオメトリ・パスでレンダリングする静的な影と、動的キャラクタ用の動的な影の2つの組み合わせで表現されている。

 なお、動的オブジェクトでも遠距離のものや、影が落ちていても落ちていなくてもわからないような小さいオブジェクト、影響範囲が小さい光源からの影については、負荷低減の見地から動的な影生成を省略する手抜き(最適化)を盛り込んでいる。

 動的な影生成には、ごく一般的な「デプスシャドウ」(シャドウマップ)技法を採用するが、いくつかの独自の改良を施している。なお、デプスシャドウ技法の詳細やその改良型についての解説は本連載のバックナンバー「3DゲームファンのためのXbox 360グラフィックス/物理エンジン講座」を参照のこと。

 独自の改良の1つ目は影品質の向上を図るために視点からの距離に応じて4枚のシャドウマップをカスケードさせて利用している点だ。1枚あたりのシャドウマップ用のデプスバッファは最大で16ビットの1,024×1,024テクセル。

 2つ目は、デプスシャドウ技法においてよく問題視される影のエッジの点滅の弊害の解消だ。デプスシャドウ技法における影輪郭の点滅は、視点が動いたときに、シャドウマップ用のテクスチャが視線ベクトルにシンクロして回転してしまうことに原因があった。

 見ている対象物が動かなくても、見ている側が動くことで、シャドウマップ内に書き出された影領域の描かれ方が変わってしまい、これが最終的なシーンに描かれた影の輪郭のブレになっていたのだ。「KILLZONE 2」では、これを改良するために、ワールド座標系でシャドウマップをカスケードさせる工夫を盛り込んだのだ。これによる影の輪郭の振動が抑えられたが、シャドウマップの利用効率が一定じゃなくなったことで、場合によっては影解像度が低くなる状況がありうるとしている。

【影生成】
1番奥(LEVEL3)は影生成なしLEVEL2。静的な影は見えるLEVEL1。静的な影と動的な影の双方が描かれている
一番手前(LEVEL0)。こちらも静的な影と動的な影の双方が描かれている動的生成された影のみ静的生成された影のみ
完成画面対象物が動かなくてもシャドウマップ内の使われ方が変わるシャドウマップを、ワールド座標系基準で回転させずにカスケードさせる工夫を盛り込んだ


■ 「KILLZONE 2」における疑似グローバルイルミネーション~Light Probe情報をSPUで球面テクスチャへ

Light Probeを可視化した画面
l=0、1、2、3… m=-l~+lにおける球面調和関数の3次元可視化図。たとえばl=3の4段目まで使うとすれば総計16個の球面調和関数を使うことになる

 今世代の3Dゲームグラフィックスにおいて、先進的なスタジオがこぞって取り入れているのが疑似的なグローバル・イルミネーション(GI:Global Illumination:大局照明)だ。

 現実世界では光源からの直接光による照明だけではなく、照明をうけたオブジェクト自体が2次光源となったり、オブジェクト同士が相互に照らし合ったりして複雑な照明効果を生んでいる。これがグローバルイルミネーションだ。特に相互反射に着目したものはラジオシティ(Radiosity)と呼ばれる。

 基本的に現在のリアルタイム3Dグラフィックスパイプラインは「(遮蔽物を考慮しない)直接光による照明だけ」しか処理されないので、GIを実装するには何らかの工夫をしなければならない。ただ、現行のGPUではGIをリアルタイム処理する能力はまだないので、事前計算を伴った、それっぽく行なう疑似手法を用いるのが主流だ。

 「KILLZONE 2」では、本連載の「ソニック・ワールド・アドベンチャー」(ソニックWA)編で紹介したライトフィールド(Light Field)法と同種の技術が採用されている。「KILLZONE 2」でもソニックWAでいうところのGIテクスチャをオフラインでレンダリングして作成してライトマップ化し、この時、同時にゲーム内シーンに対して適当な間隔でLight Probeを設置している。Light Probeとは、その位置に置いて光が全方位からどう入ってきているかを採取するもの。

 ライトマップ生成とLight Probeの算出は、全ての静的光源(動かない光源)を設置し、たっぷりと時間を掛けて相互反射にまで配慮した大局照明計算を行なう。このため、各Light Probeはそのポイントにおける全方位からやってくる「複雑な大局照明計算結果」の光を採取できる。

 例えば天井に白い蛍光灯がある狭い部屋があってその左の壁が赤く、部屋の中心にLight Probeがあったとすれば、そのLight Probeは上から白い光を受け、左から柔らかい赤(蛍光灯からの光を受けた赤い壁からの反射光)を採取することになる。

 リアルタイムレンダリング時は、このLight Probeの全方位からの光量情報を元にして、そのシーン内を動き回る動的なキャラクタ達のライティング情報として利用してやるのだ。これによってライティングされた動的キャラクタは事前計算した大局照明の結果であるライトマップと馴染むことになる。動的キャラクタが動くと、異なったLight Probeからの照明が反映されるので、あたかもそのシーンの間接光にまでに配慮されたようなライティングになり、効果として、あたかもリアルタイムにGIが行なわれているかのように見える……というわけだ。

 「KILLZONE 2」では1ステージ辺りおよそ2,500個のLight Probeを事前算出設定しており、各Light Probeは球面調和関数のl=2までの9個をRGB分3要素をKD木(KD-TREE)データで持っている。

 球面調和関数についての概念的解説は筆者の執筆した記事などを参照して欲しいが、簡単に言えば、全方位(放射状)のエネルギー分布を近似化して表現できる便利な関数のこと。可視化すると右図のようになる。概念的に喩えれば、放射状の数値分布をいくつかの係数値だけで近似再現できる、いわばMPEGやJPEGのように非可逆圧縮するメソッドということになるだろうか。

 「ソニックWA」ではこのLight Probeに相当する情報を8方向からの離散値として持っていたが、「KILLZONE 2」では9個の球面調和関数(の係数)で持ったということになる。実際のリアルタイムレンダリング時には、近接している4つのLight Probeを読みだして球面調和関数からそのLight Probeの全方位光量をデコードしてこれを元に8×8テクセルの球面状テクスチャ(球面座標系の全方位テクスチャ)を作成している。あくまで直近の4つのLight Probeを読み出してそこから加重平均的に補間している。

【Light Probe】
近隣4つのLight Probeを読み出して球面調和関数をデコードしてこのキャラクタに降り注ぐ全方位からの環境光を算出これを8×8テクセルの球面状テクスチャとして生成

 なんだか重そうな処理に思えるが、「KILLZONE 2」ではこの処理をSPUで行なっている。開発チームの発表によれば1フレーム辺りおよそ600個のLight Probe読み出しが行なわれており、一連のこの処理の負荷は1基のSPUで約13%程度だとのこと。

 実際のピクセルシェーダーでのピクセル単位のライティングでは、各ピクセルからの法線ベクトルを元に、その球面状テクスチャをサンプルしてその値を環境光扱いにしてライティングする。

 600個ものLight Probe読み出しが行なわれるのは、「KILLZONE 2」では、この球面状テクスチャをキャラクタの部位(足、胴、腕など)単位で細かく行なっていることにも起因している。その代わり上半身と下半身とで異なる間接光照明効果が得られるのでリアルに見える。

 「ソニックWA」では、キャラクタの重心オフセット値を決めてそこからライトフィールドを適用していた。「ソニックWA」はキャラクタの身長にあまり大きな差がなく、全体としてキャラクタが「固まり」として存在したために細かくやる必要がなかったのだろう。「KILLZONE 2」では立ったり、しゃがんだり、腕を振りまわしたりと人型のキャラクタが上下左右に変形するのでこのような実装が必要だったようだ。

【Light Probe その2】
動的キャラクタ(オブジェクト)を白で着色したテストショット。このシーンでは床のみが静的オブジェクト動的キャラクタ(オブジェクト)のLight Probeによる環境光と太陽光(平行光源)だけのライティング結果完成フレーム


■ まとめ~Deferred ShadingはPS3向き?

欧米で高い評価を受けた「KILLZONE 2」が日本でもいよいよ4月23日に発売される

 「KILLZONE 2」講座の前編ではDeferred Shadingを中心に解説した。Deferred Shadingは、なんとも回りくどいレンダリング技法に思えるが、動的キャラクタ数やシーン複雑性に左右されない、動的光源にスケーラブルなライティングが行なえることが利点だ。

 簡略した説明をすると、例えば前方レンダリングでは100個のキャラクタを4個の光源で照らしたとすると100×4=400回分のライティング計算が必要になるが、Deferred Shadingならば、先に100体のジオメトリをライティング無しでレンダリングして、あとで4個の光源をレンダリングしてライティングすれば、ライティング計算は4回で済む。負荷に応じてライティングに用いる光源の個数の増減も可能だ。

 前方レンダリングでは、動的光源の数が変わっただけでシェーダー内で参照する変数仕様が変わってしまうため、同じ傾向のライティングをするシェーダーでも、別のシェーダーに切り換えなければならないという、現在の煩雑なプログラマブルシェーダーアーキテクチャに影響されないことも利点だ。

 シェーダーリッチなグラフィックス表現を行なうタイトルにDeferred Shadingを採用する例が増えているのは、このあたりの利点が大きく効いているようだ。Deferred Shadingを採用した3Dゲームとしては「Bionic Commando」(CAPCOM)、「S.T.A.L.K.E.R.」(GSC Game World)、「Tabula Rasa」(NC soft)などがあり、今後も実装事例が増えていくことが予想される。

 ちなみにこのDeferred Shadingは、Xbox 360には向かないという意見もある。Xbox 360はGPUには帯域不足をカバーする目的で10MBのEDRAMが搭載されている。Xbox 360では解像度の高いフレーム、あるいはMRTでEDRAM容量の10MBを超える大量出力を伴うレンダリタングを行なう場合には、一回のレンダリングが10MBのEDRAMに収まるように分割レンダリングする必要がある。

 Deferred Shadingの場合、ジオメトリ・パスで画面全域の中間値を出力することになるが、例えば1,280×720ドットのフレームで4MRTをすると、深度バッファ含まない状態で14MBに達してしまい、10MBを優に超えてしまう。7MB×2として分割レンダリングするとしても、2分割目のレンダリング時、1分割目のレンダリングした結果はクリアされてしまう。1分割目を対比するとメモリバス消費が起きてパフォーマンスに響く。Xbox 360でもやってできなくはないが、Deferred ShadingはPS3やPC向けの方法だといえそうだ。

 また、Deferred Shadingにも弱点はある。まずよく指摘されるのが、半透明オブジェクトを効率よく処理する術がないという点だ。Deferred Shadingでは、半透明オブジェクトについては前方レンダリングで描くというのが最もシンプルな解決方法となるが、半透明描画が多いシーンではDeferred Shadingのメリットを活かせない場合も起こりうる。ただ、GPUの性能面でハンデを背負っているPS3にとっては、Deferred Shadingは有効な手法の1つであることは間違いない。今後、PS3専用タイトルを中心に採用が増えて来るかもしれない。

 

 

KILLZONE 2 (C) Sony Computer Entertainment Europe. Published by Sony Computer Entertainment Inc. Developed by Guerrilla.

(2009年 4月 17日)

[Reported by トライゼット西川善司]