この記事では、TOPネットワークで構成されるPDGについて、更に細かい解説を行います。
PDGはProcedural Dependency Graphの略で、多くの潜在的なアプリケーションを持つSideFXの最先端技術です。
もともと、SideFXがこのプロジェクトに取り組む動機は、コンテンツパイプラインの規模、自動化、分析の面での課題でした。
これらは一般にコンテンツパイプラインに適用可能な課題ですが(実際、PDGはこの一般的なコンテキストでのソリューションとして展開できます)、PDGは特に大規模なプロシージャルなコンテンツ生成の分野に焦点を置いて開発されています。
プロシージャルに生成された都市を考えてみましょう。
例えば、窓を生成する為のプロシージャルな「式」があると仮定すると、その「式」は1回だけ適用されるのではなく、数百回、数千回と適用されます。
さらに、「式」は正しい順序で適用する必要があります。まず、道路を建設し、次に道路がない場所に建物を建設し、次に窓と内装を組み立てます。
これらのことはすべて正しい順序で実行する必要があり、利用可能なすべてのコンピューティングリソースを活用して、できるだけ早く実行する必要があります。
PDGは、根本的なタスクの依存関係を解明することでこの問題を解決します。
依存関係を理解し、独立したタスクを別々のコンピューティングリソースにスケジューリングすることで、どのタスクが互いに独立しているかを理解し、スケーラビリティを最大限に引き出すことができます。
タスクは自身が完了した後に行わなければならない下流シーケンスのタスクを理解しているので、自動化をする部分がどのタスクに依存しているか理解しています。
最後に、詳細な依存関係を理解することで、各タスクが完了するたびにタスクの完了に要した時間を収集し、時間を集計することでパイプラインのボトルネックを分析できます。
名前が示すようにPDGが依存関係の問題に対処する方法は、従属グラフのプロシージャルな生成です。PDGグラフは、より複雑で明示的な従属グラフを生成する「メタグラフ」の一種です。
上の図は、この概念の実際の図です。左側のPDGグラフは、右側の明示的な依存グラフを生成しています。
右のグラフは、実際には図の示唆よりもはるかに複雑です。各「…」の間は、何百ものノードになる可能性があります。
したがって、PDGは次のような技術です。
- ノードとの複雑な依存関係を視覚的に記述する
- その依存関係記述を、実行可能でスケジューリング可能なタスクのセットに変換する
- これらのタスクをスケジューラの助けを借りて分散させ、並列に計算する
PDGが上記をどのように達成するかを知るためには、PDGの2つのコア概念、すなわちプロセッサの概念とワークアイテムの概念を理解する必要があります。
PDGで定義されるProcessorとは、何らかのワーク単位を実行できる単純な数式です。現行のPDGのリリースバージョンにおいては、Processor=実行ファイルと考えることができます。
たとえば、Microsoft C ++コンパイラであるcl.exeは、.cファイルを.objファイルに変換する式と考えることができます。
同様にレンダラは、シーン記述ファイルをイメージファイルに変換する方法を知っている数式と定義できます。 Houdini Digital Assetは入力ジオメトリをどのように変更して、出力ジオメトリに変換するかを知っている数式となります。
それに対して、ワークアイテムは、Processorが理解するデータ群を表します。 Processorはワークアイテムを取り出し、その内容を読み取り、一部の共有メディアで出力としてアクセスできるデータを生成します(これは共有ドライブ上のファイルです)。
各Processorには多数のワークアイテムが格納されており、同じProcessorのワークアイテム間に依存関係がある場合を除き、並行して作業を進めます。
PDGの「グラフ」は最低1つのプロセッサから構成できます。複数の互換性のあるワークアイテムを取得し、ワークアイテムのそれぞれを並列で実行します。したがって、単一のPDGノードであっても有用なものとなり得ます。しかしPDGノードを連鎖させるともっと面白いことが実現できます。各ワークアイテムが終了すると、下流のPDGノードは、上流のワークアイテムの結果に基づいて1つまたは複数のワークアイテムを生成する機会を得ることができます。このようにして、ワークアイテムは他のワークアイテムを生み出すことができ、これにより、親ワークアイテムと子ワークアイテムとの間に依存関係リンクが形成されます。この方法や、後述する他の方法の拡張適用により、ワークアイテム間に二次グラフを形成することができます。この二次グラフは、PDGから生成された明示的な依存グラフであり、タスクグラフと呼ばれます。タスクグラフのワークアイテムはスケジューラに渡され、ワークアイテムが使用可能な計算リソースに割り当てられます。
上記の概念を説明するための図は以下になります。
そして上の説明における、実際のPDG上でのスクリーンショットが以下になります。
ルートワークアイテム
PDGは「プロシージャルな依存の生成システム」と考えることができます。つまり、ワークアイテム間の依存関係を手続き的に生成します。
単一のワークアイテムは、他のワークアイテムを生成する可能性があります。すべての作業を開始したワークアイテムは、一種の「種」と考えることができ、「ルート」ワークアイテムとして定義されます。ルートワークアイテムには、下流ワークアイテムが定義されています。あるノードでPDGの結果を照会するとき、常にこのワークアイテムはそのルートのワークアイテムと関連しているので、ルートワークアイテムは特別な意味を持ちます。
次の図は、ルートワークアイテムの概念を示しています。
主なコンポーネント
PDGはPDGグラフによって構成されていると考えることができ、PDGが生成した明示的依存グラフである「タスクグラフ」を考えることができます。
スケジューラの3番目の部分は、依存関係が満たされているタスクを実行するためのもので、コンピューティングリソースを割り当ててそれらのタスクを完了させます。
タスクが完了すると、スケジューラはPDGグラフにさらなる計算を開始する可能性があることをタスクグラフに通知します。PDGでは、Deadline、Tractor、HQueueなどの他の様々なスケジューラを利用する可能性があるため、PDGはスケジューリングバックエンドに依存しないように設計されています。
どのスケジューラもPythonバックエンド経由でプラグインすることができます。
プロシージャルコンテンツ生成への適用
本質的にプロシージャル手法は、簡単な上流入力から複雑な下流出力を生成する傾向があります。たとえば、最初のワークアイテム「ルート」が路面を生成したとします。
それが完了すると、さらに2つの子ワークアイテムが生成され、通りの両側にそれぞれの歩道が作成されます。
それらが完了すると、歩道の上にいくつかのワークアイテムが作成され、木や街灯のようなものが作成されます。
タスクグラフが最初のルートワークアイテムから「広がっていく」傾向は、この構造の本質を捉えます。
大きなコンテンツの生成を避ける「パス」
PDGを使用すると、非常にきめ細かで詳細な依存関係を理解することができます。
詳細な依存関係を理解することにはいくつかの利点があります。その中でも特に重要なのが、大きなコンテンツ生成パスを作成する必要がなくなることです。
例えば、海洋ワークフローの例を考えてみましょう。
この例では、海洋シミュレーションに基づいて最終的な映像を生成します。 PDGがなければ、次のように4回の大きなパスで行う必要があります。
- 最初のパスでベースとなる海洋シミュレーションを行います
- 第1パスが終了すると、第2パスとしてベースの海洋シミュレーションの最上部でサーフェシングとホワイトウォーターのシミュレーションを実行します
- サーフェシングとホワイトウォーターシミュレーションの両方が完了したら、レンダリングパスを開始します
- すべてのフレームがレンダリングされたら、それらのフレームに基づいて最終的な映像を作成します
特定のパスにおいて、作業している間、その次のパスでは何も実行されていません。これは、次のパスで作業における特定のサブセットについて理解するための詳細な依存関係の情報を持っていないためであり、必要な情報が上のパスによって生成された時に初めて、作業を進めることができます。
たとえば、このワークフローでは、最初の2つのパスが完了するまで、最終的にレンダリングされるフレームのいずれも開始されません。
ベースの海洋やホワイトウォーターの設定に何か問題がある場合は、これら2つのパスで費やされた時間のすべてが無駄になります。
対照的に、フレームごとの詳細な依存関係(右の図)が得られると、ベースの海洋の最初のフレームが完成するとすぐに、サーフェィシングおよびホワイトウォーターの最初のフレームを処理することができ、これが完了したら最初のフレームの最終的なレンダリングをすぐに進めることができます。
同様の問題は、ゲームの大規模な手続き環境作成でも見られます。そこでは、詳細な依存関係がなければ、各パスが前のパスの完全な結果に依存する巨大なパスとしか見ることができず、ワールド環境を作成するまで次のパスに進めなくなります。
このスキームの下では、ビッグ・パスはビルド・ファームで長時間かけて実行する必要があり、細分化された依存関係に関する知識が不足しているため、世界のサブセットを分割して徐々に更新するのは難しいでしょう。
汎用パイプラインツールとしての適用
PDGはプロシージャルコンテンツ生成の問題に非常に適していますが、PDGの構成は完全に一般的であり、PGDの活用はHoudiniに囚われるものではありません。 Processorとワークアイテムは完全に汎用的であるため、PDGは、自動化とスケーリングの必要性などの一般的なパイプラインの問題に適用できる可能性があります。
一連のプロセッサをシンプルでリニアなチェーンで組み合わせることで、スケーラブルで視覚的なデータ駆動型のパイプラインを作成できます。
例えば、写真測量パイプラインは、メッシュを間引きし、UVを低解像度メッシュに転送し、ジオメトリファイルを書き出すプロセッサと、画像セットから高解像度メッシュを生成するプロセッサを組み合わせることによって作り出すことができます。
また、Perforceなどの汎用的なバージョン管理システムにチェックインすることもできます。
ミドルウェアとしての適用 – Houdiniエンジンへのバインディング
PDGはそれ単体で機能し、スタンドアロンツールとしての価値を提供することができますが、その価値と機能性はHoudini Engineとの統合によってさらに増幅されます。 Houdi Engine API(HAPI)は、ワークアイテムを作成し、それをPDGに直接送信できるように拡張されました。
これは、Houdini Engineを介してPDGにワークを送信し、その作業を自動化されスケーラブルな方法で並行して実行できることを意味します。また、この際送信されるワークは多くの場合Houdini Engine APIによって外部DCCツールから送られるものであり、Houdiniで作成されたものではないことが想定されます。
Houdiniへの適用 – TOPネットワークによるスケーリング
PDGはそれ単体でも動作することができますが、現在のところ基本的にはHoudiniと統合される形となっています。その結果、Houdiniにおいて内部の新しいコンテキスト、つまりTOPネットワーク(Task OPerators)が生まれました。 TOPネットワーク内では、Pythonで定義されたカスタムPDGノードとあらかじめ定義されたノードを組み合わせてPDGネットワークを形成することができます。さらに、Houdiniの他の部分の情報にアクセスし、そこからワークアイテムを作成できる事前定義されたPDGノードが用意されています。たとえば、SOPネットワークに到達し、ジオメトリの一部を抽出し、各ポイントまたはプリミティブからワークアイテムを作成できるノードがあります。これは、各ワークアイテムで作業する他のPDGノードと接続することができます。これにより、あらゆる種類の処理を行うことができるポイントまたはプリミティブに対して、完全に一般的で「ファーマブル」なforeachループを作成することができます。たとえば、すべてのポイントでSpeedTreeからツリーを作成する作業をファームに分散して並行して実行することができます。これは、100以上の “verbified” SOPノードでのみ実行できる形式の現在のSOP内部のforeachループとは対照的です。
この分散の時点では、SOPにTOPネットワークを直接インラインで埋め込むことができます。プロジェクトが進行するにつれて、更に機能は追加されていきます。