Qt 3D でライトの数を増やしてみよう

この記事は The Qt BlogIncreasing the number of lights in Qt 3D を翻訳したものです。
執筆: Svenn-Arne Dragly, 2017年12月05日

Qt 3D の Deferred Renderer では無限個のライトを使用したシーンの描画が可能ですが、Qt 3D Extras のデフォルトのマテリアルは Forward Rendering 用にできているためにライトを同時に8個までしか使用できないようになっています。いくつかのトリックを使うと9個以上のライトを定義できますが、描画時には近い順から8個のライトを選択してそれらを利用するようになっています。

以下のシーンでは、100個のライトを浮遊させていますが、一度に計算されるのは8個までのためにライトがついたり消えたりしているように見えると思います。

https://youtu.be/5k3Fd5t_KBo

別のパイプラインを利用して更なるライトを利用することは可能ではありますが(Qt 3D Studio ランタイム の場合はそうなるでしょう)、Qt 3D Extras のデフォルトのマテリアルを、Forward Rendering を用いた場合でも、より多くのライトに対応させたいと思っています。

現在の制限の1つの理由は、様々な OpenGL のアーキテクチャーの対応のためで、シェーダーに渡せる uniform データの数に厳しい制限があるものもこれには含まれています。このため、ライトの構造体の小さな配列をシェーダーに渡し、フラグメントシェーダーでライトの数だけループを回すような処理になっています。残念ながらこのループはシェーダープログラムの膨大な処理のコンパイルが必要なため、リソースの制限があるハードウェア上ではとても重たくなります。これのせいでシェーダープログラムのコンパイルが通らないというケースもあります。

強力なハードウェアに向けてライトの数を増加でき、貧弱なハードウェアではシェーダーの処理数を減らすようなソリューションの取り組みをはじめました。これは KDABの Kevin Ottens によって最近追加された Qt 3D の新しい内部のシェーダーグラフを元にしています。

シェーダーグラフは Qt 3D の画期的な機能で、最近の多くの 3D モデリングツールで採用されているマテリアルグラフによく似た構造で、シェーダーをを動的にビルドする事ができるようになりました。グラフのそれぞれのノードは関数と考えることができ、入力値のセットから出力値を導く計算として定義できます。例えば、サーフェスノードはライトの入出力角と、ライトの色とサーフェスの色からライトへの寄与を計算します。グラフのノードを接続する際に、シェーダープログラムの計算のフローを定義し、それがプログラミング言語の処理に翻訳されます。すべての計算は抽象化されているため、様々な種類のシェーダー言語(や方言)に翻訳が可能で、同じマテリアルの定義を異なるアーキテクチャ向けに生成することができます。

ライトの数の増加という観点では、シェーダーグラフによりシーンの中の個々のライトのシェーダーノードの定義が容易になります。そのグラフはシェーダーコードに変換される際に正しい数のライトの計算になります。シェーダー自体にループを持つのではなく、シェーダーが生成される際にライトの数だけループを回すようになっています。これは基本的にはループ展開に相当し、非常に効率がよくなり、より多くのライトを利用することができるようになりました。

現在はシェーダーグラフ上にライティングシステムを移行するプロトタイプを作成中です。この作業はまだまだ実験段階ですが、期待のもてる結果がたくさんでています。上記と同じシーンで100個のライトを同時に見ることができるようになりました。

https://youtu.be/zdxt_BRk-A4

これを Qt 3D Extras のデフォルトのマテリアルにする前に、複数のライトをシーンの中で集めてシェーダーに送るところの処理も変えたいと思っています。現在は描画の処理と強く結びついた実装になっていますが、それの前提になっているいくつかの仮定を排除し、ライトの情報がシェーダーに渡されるところの自由度をあげたいと思っています。これによって、同じシーンで Forward Rendering と Deferred Rendering の両方をサポートし、描画モードの切り替えができるようなアプリケーションの開発も可能になります。

この改善に興味がある方は、みなさんのプログラムの中でライトをどうしたいかを教えてせいただけるとうれしいです。


Blog Topics:

Comments