2006/10/30
Direct3D のボトルネック
コンシューマ系の組み込みハードと PC の Direct3D では、気をつけなければいけ
ない点が異なっています。思わぬボトルネックが発生します。
とあるメーカーが開発した PC 向けのタイトルのサンプルで、非常に動作が重い
ものがありました。しかもモデルデータのせいで処理が重いので、データを軽く
して欲しいとの話でした。またデータのせいで使えるビデオカードにも制約が
出てしまうとの指摘でした。
画面は 3D のフィールドを表示するシンプルな画面で、背景もキャラクタもごく
普通のモデルデータです。
ところが非常に要求スペックが高く、ためしに起動した PC では 1fps も出てい
ない状況でした。
大体予想がつきましたが、おそらく GPU ではなく CPU の方で処理が落ちている
のでしょう。見たところデータフォルダ内には細切れになったテクスチャが大量
に入っていました。
PC の場合、Direct3D の描画 API の呼び出し回数によって速度が大幅に変わります。
そのためエンジン設計の第一歩は Draw の回数を減らすことからです。
描画はできるだけまとめてばらばらのオブジェクトも一回で描画できるようにします。
Draw 呼び出しの内部ではマテリアルやレンダーステートを切り替えられないので、
マテリアルの数がそのまま描画回数の増加につながります。
テクスチャはできるだけシートにまとめ、マテリアルパラメータは可能ならば頂点
に埋め込みます。
マテリアルやシェーダーの切り替えも負荷になるので、切り替えを最小限にするため
には描画の前にソートしておく必要があります。
また ShaderModel3.0 や、ATI RADEON の ShaderModel2.0 では、ジオメトリ
インスタンシングを使うことができます。頂点ストリームにジオメトリやマテリアル
を書き込んでおくことで、一度の描画呼び出しで大量のオブジェクトを描画可能です。
つまり、描画時には必ずこのような描画を減らす工夫が必要だということです。
そうでないと描画呼び出し API の実行だけで CPU サイクルを消費してしまいます。
コンシューマ系の組み込みハードウエアでは、描画 API の Call はそれほど負荷に
ならず、テクスチャの変更もほとんどサイクル数を消費しないものがあります。
そのためつい同じような考えで描画パイプラインを設計してしまうと思わぬ
ボトルネックに苦しむことになります。
WindowsVista + Direct3D10 では、ステート等のバッファを VRAM 上に確保できる
など、より負荷を軽くするためのさまざまな工夫が施されているようです。
Draw 呼び出し回数の次に考えられる CPU のボトルネックはバッファの lock です。
例えばキャラクタのスキニング等で頂点バッファを lock して書き換えると、GPU
との同期待ちで CPU が無駄に待っている可能性があります。
シェーダーで演算すれば解決なのですが、どうしても CPU で書き込みを行う場合は
フレームバッファと同じように頂点バッファを複数持つ必要があります。頂点バッ
ファを POOL 化して、書き換えた頂点を発行するたびに使用するバッファを切り
替えていきます。
このあたりのボトルネックは、今では PIX 等の解析ツールを見れば一目瞭然で
しょう。
ない点が異なっています。思わぬボトルネックが発生します。
とあるメーカーが開発した PC 向けのタイトルのサンプルで、非常に動作が重い
ものがありました。しかもモデルデータのせいで処理が重いので、データを軽く
して欲しいとの話でした。またデータのせいで使えるビデオカードにも制約が
出てしまうとの指摘でした。
画面は 3D のフィールドを表示するシンプルな画面で、背景もキャラクタもごく
普通のモデルデータです。
ところが非常に要求スペックが高く、ためしに起動した PC では 1fps も出てい
ない状況でした。
大体予想がつきましたが、おそらく GPU ではなく CPU の方で処理が落ちている
のでしょう。見たところデータフォルダ内には細切れになったテクスチャが大量
に入っていました。
PC の場合、Direct3D の描画 API の呼び出し回数によって速度が大幅に変わります。
そのためエンジン設計の第一歩は Draw の回数を減らすことからです。
描画はできるだけまとめてばらばらのオブジェクトも一回で描画できるようにします。
Draw 呼び出しの内部ではマテリアルやレンダーステートを切り替えられないので、
マテリアルの数がそのまま描画回数の増加につながります。
テクスチャはできるだけシートにまとめ、マテリアルパラメータは可能ならば頂点
に埋め込みます。
マテリアルやシェーダーの切り替えも負荷になるので、切り替えを最小限にするため
には描画の前にソートしておく必要があります。
また ShaderModel3.0 や、ATI RADEON の ShaderModel2.0 では、ジオメトリ
インスタンシングを使うことができます。頂点ストリームにジオメトリやマテリアル
を書き込んでおくことで、一度の描画呼び出しで大量のオブジェクトを描画可能です。
つまり、描画時には必ずこのような描画を減らす工夫が必要だということです。
そうでないと描画呼び出し API の実行だけで CPU サイクルを消費してしまいます。
コンシューマ系の組み込みハードウエアでは、描画 API の Call はそれほど負荷に
ならず、テクスチャの変更もほとんどサイクル数を消費しないものがあります。
そのためつい同じような考えで描画パイプラインを設計してしまうと思わぬ
ボトルネックに苦しむことになります。
WindowsVista + Direct3D10 では、ステート等のバッファを VRAM 上に確保できる
など、より負荷を軽くするためのさまざまな工夫が施されているようです。
Draw 呼び出し回数の次に考えられる CPU のボトルネックはバッファの lock です。
例えばキャラクタのスキニング等で頂点バッファを lock して書き換えると、GPU
との同期待ちで CPU が無駄に待っている可能性があります。
シェーダーで演算すれば解決なのですが、どうしても CPU で書き込みを行う場合は
フレームバッファと同じように頂点バッファを複数持つ必要があります。頂点バッ
ファを POOL 化して、書き換えた頂点を発行するたびに使用するバッファを切り
替えていきます。
このあたりのボトルネックは、今では PIX 等の解析ツールを見れば一目瞭然で
しょう。
2006/10/28
Direct3D の Shader と HDR のさわり
DirectX は当初ものすごい勢いでバージョン番号が更新されていきました。
途中 X4 が抜けているものの、DirectX2~7 までがわずか 4年。
ところが Shader が登場した DirectX8 以降はそのペースが落ちます。
特に DirectX9 は 2002年に登場してから 4年間も使われていることになります。
以前はリアルタイム3Dのテクノロジの更新が API に直結しており、ハードウエアの
進化や新機能の追加は Direct3D API の刷新が必要でした。
ところが今では D3D API ではなく、シェーダー機能の拡張そのものにハードのパワー
が注がれるようになっています。
「シェーダーが必要なわけ」
でも書いたように、もはや 3D アルゴリズムの進化とハードウエアの拡張は別物です。
ソフトウエア技術者はシェーダーという自由の中で、アクセラレータの恩恵を受け
つつさまざまなアルゴリズムを開拓することができます。
そしてハードウエアメーカーは GPU の汎用的なシェーダーパワーの拡充に専念する
ことができるわけです。
もうすぐ Direct3D10 とともに ShaderModel4.0 が登場します。
ハードウエアの都合に強く依存していたシェーダーの仕様は、徐々にその影響力を
弱めています。ますます汎用的になっています。
レンダリングのアルゴリズムは、ハードウエアロジックではなくプログラマに委ねら
れているわけです。さらに近い将来、プログラマではなくグラフィックデザイナー
範疇に含まれるようになるかもしれません。
一般的に画像データは RGB の各色を 0~255 の 256段階で持ちます。RGBがそれぞれ
256段階なので、256×256×256 = 16777216 のおよそ 1677万色の表現が可能です。
これを 24bit カラーといったりフルカラー画像と呼ぶことがありました。
フレームバッファも最終的には 24bit カラーなので、リアルタイムレンダリングの
ピクセルカラー演算も 0~255 の 8bit 整数が使われていました。
ShaderModel2.0 以降、PixelShader 内部は 24~32bit の浮動少数点演算に拡張され
ています。モニタへの出力は 1677万色なので、色数を見たらフルカラーを超えて
おりオーバースペックです。
PixelShader の演算はベクトルや座標値など、もはやカラーの値だけでは済まない
からです。
またカラー値そのものも HDR で持つことが多くなりました。演算中は自然界の数値
を模した高いダイナミックレンジを保っておき、最終的にモニタに出力する直前に
人間の可視範囲で切り取るわけです。
3D のワールドマップ上でキャラクタやオブジェクトを動かしておき、任意のカメラ
で見える範囲をレンダリングするのに似ています。
自然界の微弱なものから強烈な光まで、幅広い光の中から任意のカメラで好きな
部分を「可視可能な領域」としてレンダリングできるようになります。
途中 X4 が抜けているものの、DirectX2~7 までがわずか 4年。
ところが Shader が登場した DirectX8 以降はそのペースが落ちます。
特に DirectX9 は 2002年に登場してから 4年間も使われていることになります。
以前はリアルタイム3Dのテクノロジの更新が API に直結しており、ハードウエアの
進化や新機能の追加は Direct3D API の刷新が必要でした。
ところが今では D3D API ではなく、シェーダー機能の拡張そのものにハードのパワー
が注がれるようになっています。
「シェーダーが必要なわけ」
でも書いたように、もはや 3D アルゴリズムの進化とハードウエアの拡張は別物です。
ソフトウエア技術者はシェーダーという自由の中で、アクセラレータの恩恵を受け
つつさまざまなアルゴリズムを開拓することができます。
そしてハードウエアメーカーは GPU の汎用的なシェーダーパワーの拡充に専念する
ことができるわけです。
もうすぐ Direct3D10 とともに ShaderModel4.0 が登場します。
ハードウエアの都合に強く依存していたシェーダーの仕様は、徐々にその影響力を
弱めています。ますます汎用的になっています。
レンダリングのアルゴリズムは、ハードウエアロジックではなくプログラマに委ねら
れているわけです。さらに近い将来、プログラマではなくグラフィックデザイナー
範疇に含まれるようになるかもしれません。
一般的に画像データは RGB の各色を 0~255 の 256段階で持ちます。RGBがそれぞれ
256段階なので、256×256×256 = 16777216 のおよそ 1677万色の表現が可能です。
これを 24bit カラーといったりフルカラー画像と呼ぶことがありました。
フレームバッファも最終的には 24bit カラーなので、リアルタイムレンダリングの
ピクセルカラー演算も 0~255 の 8bit 整数が使われていました。
ShaderModel2.0 以降、PixelShader 内部は 24~32bit の浮動少数点演算に拡張され
ています。モニタへの出力は 1677万色なので、色数を見たらフルカラーを超えて
おりオーバースペックです。
PixelShader の演算はベクトルや座標値など、もはやカラーの値だけでは済まない
からです。
またカラー値そのものも HDR で持つことが多くなりました。演算中は自然界の数値
を模した高いダイナミックレンジを保っておき、最終的にモニタに出力する直前に
人間の可視範囲で切り取るわけです。
3D のワールドマップ上でキャラクタやオブジェクトを動かしておき、任意のカメラ
で見える範囲をレンダリングするのに似ています。
自然界の微弱なものから強烈な光まで、幅広い光の中から任意のカメラで好きな
部分を「可視可能な領域」としてレンダリングできるようになります。
2006/10/25
リアルタイム 3D レンダリングで半透明描画が重い話 (2)
ゲームなどリアルタイム 3D のレンダリングでは、フィルレートがますます厳しく
なります。これはもう当たり前の状態だといえます。
Xbox360 であれ PS3 であれハードウエアの性能は向上したものの、より高い
解像度が求められるようになっているからです。
しかも開発者側も、フィルを無尽蔵に消費できた特殊な PS2 の開発に長いこと浸り
きってしまっていました。
Xbox360 や PS3 の開発がかなり進行している今となっては、実作業を経験すれば
もうこの問題は十分理解できているでしょう。4~5年前の Xbox の開発では
PS2 系デザイナーとプログラマとの間で何度も衝突することがありました。
コンシューマでは、PC 向けビデオカードよりもさらにバス帯域が限られてくるので
さらに描画ピクセル数をきちんと管理する必要が生じます。
なお、Wii に関しては次の記事を見る限り、シェーダーが無く描画機能も非常に
限られている可能性があります。フィルや描画のバランスがどのように設計されて
いるのかはわかりません。
http://pc.watch.impress.co.jp/docs/2006/0920/kaigai301.htm
古くはリアルタイムレンダリングの場合、データ仕様をポリゴン数で切りました。
トランスフォームやクリッピング、ライティング、スキニングなど、ジオメトリ
演算の方が負荷が高かったからです。
もっと厳密に言えばデータ負荷の目安はポリゴン数よりも頂点数です。
今のハードの場合、呼び出し方を間違えなければ頂点数はそれなりに出るし、
一度ストリームに乗せてしまえば GPU だけで全部やってくれます。
むしろシェーダーによって重いピクセルが多いので、如何に描画ピクセルを減らす
かが負荷の目安となります。なので、データ仕様はどちらかといえばシェーダー
毎のピクセル負荷と面積で切ることになります。
もちろん面積はオクルージョンカリングが有効な条件を満たしているかどうかが
鍵です。あらかじめ Z バッファを作っておくか、常にカメラの手前から描画する
ことでレンダリングするピクセル数はほぼ一定量になり、ピーク負荷も求まります。
例えばフルにノーマルマップを使うなど重い背景データがあったとします。
この背景のマップオブジェクトのシェーダーが一番重いとわかっているなら、背景が
画面いっぱいに描画されいてるケースで最も負荷が高くなります。
キャラがカメラの手前ぎりぎりまで近寄って、どんなにアップで表示されようとも
負荷は上がりません。むしろ描画すべき背景の面積が減って相殺され、かえって
負荷が軽くなるわけです。
ただしこの負荷の計算はあくまで「alpha 値を含まない不透明ポリゴン」にのみ
当てはまります。カメラアングルや状況によってめまぐるしくピクセル負荷を上げる
要因となるのは「影」と「エフェクト」です。
影は今のハードウエアと描画アルゴリズムではとにかく(ひたすら)重い処理です。
機会があったら解説します。
またエフェクトでは煙や光物など、半透明のオブジェクトが画面いっぱいに重なって
描画されるともう終わりです。処理落ちどころではありません。
この2つのピクセル負荷は一定のピーク値として計算できないので、非常に苦しい
ところです。
またエフェクトのようにあとから乗せるパーティクル系のオブジェクトでなくても、
マップとして配置する半透明のガラス等でも別の原因で負荷が高くなります。
さらに木々の葉っぱなど、Alpha や texkill でピクセルを捨てるケースがあると
オクルージョンカリングが無効になることがあります。
それどころか、オクルージョンカリングのために先に Z バッファだけレンダリング
する場合も、半透明や抜きのあるポリゴンは完全に先行レンダリングできません。
GPUの負荷
・エフェクトなど半透明ものは完全に追加のピクセル描画となる
・パーティクルは重なることが多く、カメラ位置によって面積が極端に変化する
・マップ配置物でも透過や抜きはオクルージョンカリングを阻害する
CPUの負荷
・加算以外の半透明オブジェクトは描画時にZソートが必要となる
だから alpha 成分を含む半透明オブジェクトは、エフェクトにしろマップ配置に
しろ大量かつアップで描画されると重いのです。
なります。これはもう当たり前の状態だといえます。
Xbox360 であれ PS3 であれハードウエアの性能は向上したものの、より高い
解像度が求められるようになっているからです。
しかも開発者側も、フィルを無尽蔵に消費できた特殊な PS2 の開発に長いこと浸り
きってしまっていました。
Xbox360 や PS3 の開発がかなり進行している今となっては、実作業を経験すれば
もうこの問題は十分理解できているでしょう。4~5年前の Xbox の開発では
PS2 系デザイナーとプログラマとの間で何度も衝突することがありました。
コンシューマでは、PC 向けビデオカードよりもさらにバス帯域が限られてくるので
さらに描画ピクセル数をきちんと管理する必要が生じます。
なお、Wii に関しては次の記事を見る限り、シェーダーが無く描画機能も非常に
限られている可能性があります。フィルや描画のバランスがどのように設計されて
いるのかはわかりません。
http://pc.watch.impress.co.jp/docs/2006/0920/kaigai301.htm
古くはリアルタイムレンダリングの場合、データ仕様をポリゴン数で切りました。
トランスフォームやクリッピング、ライティング、スキニングなど、ジオメトリ
演算の方が負荷が高かったからです。
もっと厳密に言えばデータ負荷の目安はポリゴン数よりも頂点数です。
今のハードの場合、呼び出し方を間違えなければ頂点数はそれなりに出るし、
一度ストリームに乗せてしまえば GPU だけで全部やってくれます。
むしろシェーダーによって重いピクセルが多いので、如何に描画ピクセルを減らす
かが負荷の目安となります。なので、データ仕様はどちらかといえばシェーダー
毎のピクセル負荷と面積で切ることになります。
もちろん面積はオクルージョンカリングが有効な条件を満たしているかどうかが
鍵です。あらかじめ Z バッファを作っておくか、常にカメラの手前から描画する
ことでレンダリングするピクセル数はほぼ一定量になり、ピーク負荷も求まります。
例えばフルにノーマルマップを使うなど重い背景データがあったとします。
この背景のマップオブジェクトのシェーダーが一番重いとわかっているなら、背景が
画面いっぱいに描画されいてるケースで最も負荷が高くなります。
キャラがカメラの手前ぎりぎりまで近寄って、どんなにアップで表示されようとも
負荷は上がりません。むしろ描画すべき背景の面積が減って相殺され、かえって
負荷が軽くなるわけです。
ただしこの負荷の計算はあくまで「alpha 値を含まない不透明ポリゴン」にのみ
当てはまります。カメラアングルや状況によってめまぐるしくピクセル負荷を上げる
要因となるのは「影」と「エフェクト」です。
影は今のハードウエアと描画アルゴリズムではとにかく(ひたすら)重い処理です。
機会があったら解説します。
またエフェクトでは煙や光物など、半透明のオブジェクトが画面いっぱいに重なって
描画されるともう終わりです。処理落ちどころではありません。
この2つのピクセル負荷は一定のピーク値として計算できないので、非常に苦しい
ところです。
またエフェクトのようにあとから乗せるパーティクル系のオブジェクトでなくても、
マップとして配置する半透明のガラス等でも別の原因で負荷が高くなります。
さらに木々の葉っぱなど、Alpha や texkill でピクセルを捨てるケースがあると
オクルージョンカリングが無効になることがあります。
それどころか、オクルージョンカリングのために先に Z バッファだけレンダリング
する場合も、半透明や抜きのあるポリゴンは完全に先行レンダリングできません。
GPUの負荷
・エフェクトなど半透明ものは完全に追加のピクセル描画となる
・パーティクルは重なることが多く、カメラ位置によって面積が極端に変化する
・マップ配置物でも透過や抜きはオクルージョンカリングを阻害する
CPUの負荷
・加算以外の半透明オブジェクトは描画時にZソートが必要となる
だから alpha 成分を含む半透明オブジェクトは、エフェクトにしろマップ配置に
しろ大量かつアップで描画されると重いのです。
2006/10/24
リアルタイム 3D レンダリングで半透明描画が重い話 (1)
それまでコンシューマをやっていたチームが、新たに PC系ビデオカードでゲームを
作ろうと評価を始めると、エフェクトなど半透明の描画が遅いので引っかかって
しまうことがあるようです。
でもよくよく話を聞いているとポリゴンを重ねすぎているだけのように見えます。
半透明の描画が通常のポリゴン描画よりも遅いのは当たり前です。
唯一当たり前じゃなかった特殊なハードが PS2 です。
PS2 には PixelShader どころかマルチテクスチャ等の pixel 演算系機能が無いので
表現力を上げるにはマルチパスを用いる必要がありました。
なのでエフェクトもひたすらポリゴンを重ねて半透明を大量に使う傾向があります。
PS2 は GPU (GS) にオンチップで VRAM を搭載していて、その転送バスは 2560bit
(147MHz で 47GB/sec) もあります。16 pixel/sec と並列度も高く、稀に見る
フィルレートの高さを持っていました。
これなら半透明など Pixel の Read/Write を頻繁に繰り返してもさほど速度が
落ちません。
オンチップでバスの太さを選んだ代わりに容量が犠牲になっており、VRAM はわずか
4M byte しかありませんでした。
4M byte だとフレームバッファだけでも一杯になるので、さらにインターレースを
用いて半分(640x240)で済ませたり、横の解像度を若干削ったり(512)します。
例えば 640x480 で color 32bit, depth 32bit だと 2.4M と半分以上も消費します。
512x240 まで削ると 1Mbyte くらいで収まります。
フレームバッファが小さくなるとさらにフィルの負担が減ることになります。
もちろん半透明といっても、等視点が変わるケースではソートが必要になるため
完全なコストフリーではありません。だけど他のプラットフォームに比べたら
圧倒的に(異常に)速かったわけです。
そんな作り方に慣れてしまっていると他のハードを使ったときに困ってしまいます。
半透明は極力減らすようにとデザイナーに伝えても「前はこうやって作ってたから」
となかなか理解してもらえないのです。
例えば同世代(?)の Xbox は、CPU と共有のバスで 6.4GB/sec の帯域を持っています。
その代わり 64MByte 全部に GPU が直接アクセスできます。
pixel 並列度で 1/4、バスの転送能力で 1/7.5、だけど VRAM は 16倍。そして
マルチテクスチャやプログラマブルなシェーダーを搭載しています。
この場合半透明をひたすら重ねる作り方は自分の首を絞めるようなもので、できる
限り重ね描きを減らさなければなりません。
リッチな表現はマルチテクスチャやシェーダーを使えばいいので、むしろマルチパス
など重ねて描画する必然性が少ないともいえます。
同じようにいまどきの PC のビデオカードも、メモリアクセスが無尽蔵にできる
わけではありません。GPU 自体の膨大な演算能力に比べるとバス帯域はそれなりに
限界があります。
例えば GeForce79000GTX のメモリが 256bit バスの 1600MHz だとすると
51.2GB/sec です。これでもべらぼうに速いんだけど数値上は PS2 の 47GB/sec と
それほど差がありません。
そして PC はよりハイレゾが求められるので、例えば 1920x1200 だと 32bit color,
32bit depth のフレームバッファだけで 18Mbyte です。
たったこれだけでも必要な転送量は 7~18倍 にもなってしまいます。
HDR をまじめにやると color は 64bit です。
この描画面積を考えると PS2 比の転送能力はずっと落ちていくことになります。
それだけ PS2 が特殊だったといえます。
できる限りピクセルを重ねずに、ピクセル1つにかける演算を重視します。
GC, Xbox1, Xbox360, PS3, PC (D3D9) と、その傾向は徐々に強くなっています。
半透明が重いのは当たり前という前提でまず描画の設計を見直しましょう。
作ろうと評価を始めると、エフェクトなど半透明の描画が遅いので引っかかって
しまうことがあるようです。
でもよくよく話を聞いているとポリゴンを重ねすぎているだけのように見えます。
半透明の描画が通常のポリゴン描画よりも遅いのは当たり前です。
唯一当たり前じゃなかった特殊なハードが PS2 です。
PS2 には PixelShader どころかマルチテクスチャ等の pixel 演算系機能が無いので
表現力を上げるにはマルチパスを用いる必要がありました。
なのでエフェクトもひたすらポリゴンを重ねて半透明を大量に使う傾向があります。
PS2 は GPU (GS) にオンチップで VRAM を搭載していて、その転送バスは 2560bit
(147MHz で 47GB/sec) もあります。16 pixel/sec と並列度も高く、稀に見る
フィルレートの高さを持っていました。
これなら半透明など Pixel の Read/Write を頻繁に繰り返してもさほど速度が
落ちません。
オンチップでバスの太さを選んだ代わりに容量が犠牲になっており、VRAM はわずか
4M byte しかありませんでした。
4M byte だとフレームバッファだけでも一杯になるので、さらにインターレースを
用いて半分(640x240)で済ませたり、横の解像度を若干削ったり(512)します。
例えば 640x480 で color 32bit, depth 32bit だと 2.4M と半分以上も消費します。
512x240 まで削ると 1Mbyte くらいで収まります。
フレームバッファが小さくなるとさらにフィルの負担が減ることになります。
もちろん半透明といっても、等視点が変わるケースではソートが必要になるため
完全なコストフリーではありません。だけど他のプラットフォームに比べたら
圧倒的に(異常に)速かったわけです。
そんな作り方に慣れてしまっていると他のハードを使ったときに困ってしまいます。
半透明は極力減らすようにとデザイナーに伝えても「前はこうやって作ってたから」
となかなか理解してもらえないのです。
例えば同世代(?)の Xbox は、CPU と共有のバスで 6.4GB/sec の帯域を持っています。
その代わり 64MByte 全部に GPU が直接アクセスできます。
pixel 並列度で 1/4、バスの転送能力で 1/7.5、だけど VRAM は 16倍。そして
マルチテクスチャやプログラマブルなシェーダーを搭載しています。
この場合半透明をひたすら重ねる作り方は自分の首を絞めるようなもので、できる
限り重ね描きを減らさなければなりません。
リッチな表現はマルチテクスチャやシェーダーを使えばいいので、むしろマルチパス
など重ねて描画する必然性が少ないともいえます。
同じようにいまどきの PC のビデオカードも、メモリアクセスが無尽蔵にできる
わけではありません。GPU 自体の膨大な演算能力に比べるとバス帯域はそれなりに
限界があります。
例えば GeForce79000GTX のメモリが 256bit バスの 1600MHz だとすると
51.2GB/sec です。これでもべらぼうに速いんだけど数値上は PS2 の 47GB/sec と
それほど差がありません。
そして PC はよりハイレゾが求められるので、例えば 1920x1200 だと 32bit color,
32bit depth のフレームバッファだけで 18Mbyte です。
たったこれだけでも必要な転送量は 7~18倍 にもなってしまいます。
HDR をまじめにやると color は 64bit です。
この描画面積を考えると PS2 比の転送能力はずっと落ちていくことになります。
それだけ PS2 が特殊だったといえます。
できる限りピクセルを重ねずに、ピクセル1つにかける演算を重視します。
GC, Xbox1, Xbox360, PS3, PC (D3D9) と、その傾向は徐々に強くなっています。
半透明が重いのは当たり前という前提でまず描画の設計を見直しましょう。
2006/10/23
シェーダーが必要なわけ
もうすぐ PS3 が登場して、ようやくメジャーハードでハードウエアシェーダーが
当たり前になります。1年前に登場した Xbox360 を筆頭に、ShaderModel3.0 が
リアルタイムレンダリングで必須になるわけです。
本当は 2002年に発売された Xbox1 に ShaderModel1.x が搭載されており
シェーダーの時代はとっくに始まっていました。
あまり注目されなかったのは販売台数のせいもありますが、ShaderModel1.x では
機能的制約が大きかったのも一因でしょう。
特に PixelShader で使用可能なステップ数は 演算8+テクスチャ4 の 12個で、
演算制度も 9~12bit 程度の固定少数でした。
もちろん海外での事情は異なっており、Xbox も PC ゲームも人気があるので
シェーダーのノウハウの蓄積はずいぶん先行しているといえます。
シェーダーの登場によって、開発するプログラマの手間は結構増大します。
固定機能の時代はハードに設定すれば勝手にやってくれたジオメトリやライトの
演算も、まるで時代が逆行したかのように自分でやらなければいけなくなりました。
特に初期のシェーダーはアセンブリ言語で記述していたため、拒否反応を示す
人も多かったようです。
ではなぜそこまでしてシェーダーが必要なのでしょうか。
ハードウエアロジックでの実装はたいへん時間がかかると考えられます。
設計から試作、量産まで、実際に動いて使えるようになるまでどれだけの手間と
時間がかかるか想像もできません。
それでも GPU はテクノロジの進化によってさまざまな機能を実装できるように
なりました。もちろんひたすら高速化のために並列度を上げていけばいいんですが、
それだとトランジスタ数よりも先に、メモリ速度やバス帯域が限界に到達して
しまいます。
そのため、ただただ速度を上げるよりも、より美しい描画を行うために機能を割く
必要が生じます。
ただしこの分野はアルゴリズムの問題であり、どんなアルゴリズムを、どんな仕様
でハードで実装すればいいのか取捨選択するのが難しいのです。
アルゴリズムの研究の進化も早いですから。
だったらプログラマが自由に命令を選択できる方がいいのではないか、そう考える
のも自然でしょう。
ハードウエアシェーダーの登場によって、プログラマが自由にハードウエアの演算
ロジックを変更できるようになりました。
プログラマがハードの機能を選択するのに必要な時間はごくわずかです。いくらでも
設計と試行、フィードバックを繰り返すことができるのです。
ハードロジックを設計してチップを製造する時間とは比較になりません。
ハードウエアアクセラレーションの恩恵を受けつつ新しいアルゴリズムの開発が
短期間でできるようになり、一気にリアルタイムグラフィックスの分野が華やかに
なりました。
アルゴリズムを開拓する人にとってはたいへん魅力的なものです。
そしてシェーダーはハードウエアでしかできなかったさまざまなアルゴリズムを
アプリケーション化してくれます。他の人が作ったシェーダーをもらってきて
使うこともできるわけです。
もう1点、シェーダーがどうしても必要だった理由があります。
GPU の開発会社や Direct3D 等の API を設計する Microsoft 等と、実際にゲーム
等を開発する現場とはどうしてもそれなりの距離や隔たりがあります。
実際に現場が欲しい、リアルタイムレンダリングで欲しい機能と、ハードに実装
される機能は必ずしも一致していませんでした。
頂点カラーの演算方法、値の持ち方、ジオメトリブレンディングの仕様、ライティ
ングの仕様など。
固定機能の時代は、使わない機能やオーバースペックな機能であってもハードに
実装されているため使わざるを得ませんでした。また API の設計によっても
制限を受けます。
むしろ DirectX3~6 等、CPU だけでジオメトリ演算を行っていた時代の方が
ゲームにあわせて自由に頂点や演算を設計し、不要な演算は徹底的に省いて必要
最小限にすることができました。
DirectX7 世代のハードで Hardware Transform and Lighting が搭載され、
演算が極めて高速になったのは望んでいたことでした。
が、速度は速くなったのだけど、逆に使いづらい制約も増えたなと感じたものです。
DirectX8 でシェーダーが登場し、不満だった部分も全部再設計できるようになり
ました。CPU 演算時代の自由度と、GPU の速度の両方を手に入れたのだから
シェーダーは最高です!
当たり前になります。1年前に登場した Xbox360 を筆頭に、ShaderModel3.0 が
リアルタイムレンダリングで必須になるわけです。
本当は 2002年に発売された Xbox1 に ShaderModel1.x が搭載されており
シェーダーの時代はとっくに始まっていました。
あまり注目されなかったのは販売台数のせいもありますが、ShaderModel1.x では
機能的制約が大きかったのも一因でしょう。
特に PixelShader で使用可能なステップ数は 演算8+テクスチャ4 の 12個で、
演算制度も 9~12bit 程度の固定少数でした。
もちろん海外での事情は異なっており、Xbox も PC ゲームも人気があるので
シェーダーのノウハウの蓄積はずいぶん先行しているといえます。
シェーダーの登場によって、開発するプログラマの手間は結構増大します。
固定機能の時代はハードに設定すれば勝手にやってくれたジオメトリやライトの
演算も、まるで時代が逆行したかのように自分でやらなければいけなくなりました。
特に初期のシェーダーはアセンブリ言語で記述していたため、拒否反応を示す
人も多かったようです。
ではなぜそこまでしてシェーダーが必要なのでしょうか。
ハードウエアロジックでの実装はたいへん時間がかかると考えられます。
設計から試作、量産まで、実際に動いて使えるようになるまでどれだけの手間と
時間がかかるか想像もできません。
それでも GPU はテクノロジの進化によってさまざまな機能を実装できるように
なりました。もちろんひたすら高速化のために並列度を上げていけばいいんですが、
それだとトランジスタ数よりも先に、メモリ速度やバス帯域が限界に到達して
しまいます。
そのため、ただただ速度を上げるよりも、より美しい描画を行うために機能を割く
必要が生じます。
ただしこの分野はアルゴリズムの問題であり、どんなアルゴリズムを、どんな仕様
でハードで実装すればいいのか取捨選択するのが難しいのです。
アルゴリズムの研究の進化も早いですから。
だったらプログラマが自由に命令を選択できる方がいいのではないか、そう考える
のも自然でしょう。
ハードウエアシェーダーの登場によって、プログラマが自由にハードウエアの演算
ロジックを変更できるようになりました。
プログラマがハードの機能を選択するのに必要な時間はごくわずかです。いくらでも
設計と試行、フィードバックを繰り返すことができるのです。
ハードロジックを設計してチップを製造する時間とは比較になりません。
ハードウエアアクセラレーションの恩恵を受けつつ新しいアルゴリズムの開発が
短期間でできるようになり、一気にリアルタイムグラフィックスの分野が華やかに
なりました。
アルゴリズムを開拓する人にとってはたいへん魅力的なものです。
そしてシェーダーはハードウエアでしかできなかったさまざまなアルゴリズムを
アプリケーション化してくれます。他の人が作ったシェーダーをもらってきて
使うこともできるわけです。
もう1点、シェーダーがどうしても必要だった理由があります。
GPU の開発会社や Direct3D 等の API を設計する Microsoft 等と、実際にゲーム
等を開発する現場とはどうしてもそれなりの距離や隔たりがあります。
実際に現場が欲しい、リアルタイムレンダリングで欲しい機能と、ハードに実装
される機能は必ずしも一致していませんでした。
頂点カラーの演算方法、値の持ち方、ジオメトリブレンディングの仕様、ライティ
ングの仕様など。
固定機能の時代は、使わない機能やオーバースペックな機能であってもハードに
実装されているため使わざるを得ませんでした。また API の設計によっても
制限を受けます。
むしろ DirectX3~6 等、CPU だけでジオメトリ演算を行っていた時代の方が
ゲームにあわせて自由に頂点や演算を設計し、不要な演算は徹底的に省いて必要
最小限にすることができました。
DirectX7 世代のハードで Hardware Transform and Lighting が搭載され、
演算が極めて高速になったのは望んでいたことでした。
が、速度は速くなったのだけど、逆に使いづらい制約も増えたなと感じたものです。
DirectX8 でシェーダーが登場し、不満だった部分も全部再設計できるようになり
ました。CPU 演算時代の自由度と、GPU の速度の両方を手に入れたのだから
シェーダーは最高です!