On this page |
概要 ¶
ジオメトリネットワークでは、ネットワークの一部(すべてのノードが“コンパイル可能”であれば)を コンパイルブロック の中に格納することができます。 ある意味では、コンパイルブロックは、その中のノード群が1つのノードであるかのように動作します。
これは、ネットワークの挙動にいくつか制限を強いることになりますが、それに合った状況においては潜在的に大きなメリットをもたらす可能性があります。
-
主なメリットは、for-eachループのマルチスレッド化です。このfor-eachループのネットワークは、膨大な数のピースに対してそれぞれ同じノードのブロックを実行します。コンパイルブロックを使用することで、Houdiniはそれらの反復処理をマルチコアで展開することができます。
-
他のメリットは、OpenCLをもっと効率的に使用できることです。通常であれば、ノードがグラフィックカード上のジオメトリを処理したとしても、潜在的に他のノードがそのジオメトリにアクセスを試みる可能性があるので、ノード毎にジオメトリをメインメモリ内にコピーしなければなりません。しかし、コンパイルブロックでは、複数のOpenCLベースのノードがグラフィックカード上にデータをコピーしてその結果を戻すという手間を省いて処理ができるようにそのデータを維持することができるので、処理速度が速くなります。
-
通常のネットワークでは、各ノードは理論的にそのノードが処理するジオメトリのコピーを作成します。これを実際に効率化できるように最適化がたくさん施されていますが、それでも負荷があります。コンパイルブロックでは、外部参照が許可されていないので、それらのノードは同じジオメトリに対してインプレース(直接データを書き換え)で動作することができます。このおかげで、コンパイルブロックをさらに高速化することができます。
制限事項 ¶
残念ながら、これらのメリットを得るために、Houdiniのダイナミクスと流体で動作させるのにいくつかの柔軟性を制限しなければなりませんでした。
“コンパイル可能”なノードのみに対応
コンパイルブロック内でコンパイルできるように変更されたノードだけを使用することができます。ネットワークエディタでバッジを有効にすることで、コンパイルブロックで使用できないノードを確認することができます。
私たちは、要望に基づいてノードの変換を続けています。おそらく、(数百もの)既存のSOPすべてに到達しそうにありません。コンパイルブロックで使用したいノードがまだ変換されていないようでしたら、私たちに知らせてください。
stamp()
エクスプレッションには対応していません
stampエクスプレッション関数は、格別に極まりない難しいアクションです。この関数は、ネットワーク内のどこかの他のノードをクックできるノードに依存しています。この完全に自由な関数は、コンパイルブロックで使用することはできません。
ローカル変数とコンポーネント毎のエクスプレッションには対応していません
ノードがコンパイルブロックの一部になっている時、そのアルゴリズムは、そのブロックの演算にコンパイルされ、そのパラメータは残ったままになります。 エクスプレッションはジオメトリ内のコンポーネント毎に評価されません 。ジオメトリ全体に対して“事前に”静的に動作するエクスプレッション(例えば、入力番号からの読み込み)のみが動作します。
コンポーネント毎に何かを処理する(例えば、Pointアトリビュートの値に基づいてポイントを動かす)必要がある場合、Attribute WrangleなどのVEXベースのノードを使用する必要があります。
(stamp()
とは違い、この制限事項は、その必要性に応じて、いつか解除される可能性があります。)
名前による内側ジオメトリ参照に対応していません
通常では、他のノードに関する情報が必要な時は、エクスプレッションを評価して、そのパスでそのノードを参照することができます。
例えば、npoints("/obj/sphere1")
は、ノードのジオメトリ内のポイント数を取得することができます。このエクスプレッションは、あまり効率的ではないですが動作します。
コンパイルブロックでは、そのノードパスを使ってノード内のジオメトリを参照することができません。
コンパイルブロックで同じ事をするには、内側の名前の参照をSpare入力の参照に置換する必要があります。
パスでブロック内のノード上の チャンネル値 を 参照することはできます (例えば、ch("../sphere1/tx")
)。point
エクスプレッションと同様に ジオメトリ を読み込むことはできません。
コンパイルブロックの 外側 のジオメトリを 参照することはできます が、その外側のノードへのすべてのアクセスはロックによって直列化されるので、おそらくスレッド化したループではパフォーマンスが低下します。 この場合、代わりにSpare入力を使用してください。
コンパイルブロックの外側のノードは、その内側のノードのジオメトリを参照することができますが、そうすることによって、コンパイルのメリットがないまま普通に内側ノード(とディペンデンシー)をクックします。
エクスプレッションはノードの直接入力から読み込むことができません
エクスプレッションは、ノードの直接入力(例えば、point(0, …)
またはnpoints(0)
)からデータを読み込むことができません。入力ノードを参照するにはSpare入力を使用する必要があります。
この制限事項は、将来のバージョンのHoudiniでは最低でも入力0に対して部分的に解除される予定です。
無効化/非表示のパラメータは評価されません
これは、たとえコンパイルブロック外であっても、コンパイル可能なSOPすべてに対して当てはまります。 以前は、各SOPがそれ自身のクックコードで評価するパラメータを決定していました。今では、そのクックロジックはパラメータ評価とは別になっています。 つまり、パラメータを事前評価する必要があります。無効化パラメータに対して偽りの時間依存を作成しないように(重い処理の評価にならないように)、その事前評価は、無効化/非表示のパラメータをスキップします。
Stop Conditionには対応していません
For Eachノードの Stop Condition は、コンパイルブロック内では対応していません。
Note
コンパイルブロックの開発の時点で、特にプロダクション環境では、おそらく効率性を最大限に上げるためにコンパイルブロックをどこにでも追加しようと躍起になってしまいますが、それを我慢した方が良いでしょう。 この欠点は、その恩恵がその努力に見合わないことがよくあることです。
-
コンパイルブロックによって非常に恩恵が得られるところをターゲットにしてください。例えば、膨大な数のピースに対する反復処理です。
-
ネットワークを動作させて仕上げてから、そのプロファイリングに基づいて、遅い部分のネットワークをコンパイルブロックに変換すると良いでしょう。
How to ¶
Houdiniは、1つ以上のCompile Block Beginノードとそれに呼応するCompile Block Endノード間のすべてのノードのコンパイルを試みます。
To... | Do this |
---|---|
コンパイルブロックを作成する |
|
コンパイルループ ¶
ループの中にコンパイルブロックを置くのではなく、コンパイルブロックの 中に ループを置きます。
トップレベルのFor-Each Block Endノードの Multithread when Compiled を有効にします。 このチェックボックスを有効にすることで、このループの別々の反復を別々のコアに分散させるようにHoudiniに伝えます。 分散タスクの数が爆発的に増加しないように、外側のループにのみこれを有効にした方が良いでしょう。
ブロックの入れ子化 ¶
コンパイルブロックとループを使用する時、注意して各ブロックの“境界”でBegin/Endノードを使って各ブロックを適切にカプセル化してネスト化しなければなりません。 視覚的に、ネットワーク内では、ブロックを横断するワイヤーは、ブロックのBeginノードに接続されたワイヤーのみにしてください。
このネットワークでは、merge3
のワイヤーがブロック境界を横断しています。これは、通常のクックで有効であり、Houdiniは、反復毎にそのパスを再クックします。
コンパイルブロック内のループは、別々のユニットとしてコンパイルされますが、それらのループはそれら自身が独立している必要があります。
そのmergeの前にBlock Beginノードを挿入することで、コンパイルとループのブロックが適切に入れ子化されるように修正しました。このBeginノードの Method パラメータを Fetch Input に設定しました。
Spare入力 ¶
制限事項のセクションで説明している通り、コンパイルブロック内ではジオメトリのエクスプレッションは、ノードの直接入力を参照することができません。さらには、コンパイルブロック内のノードを名前で参照することができません。 この規則では、クックする内容に対して“驚き”のあること(動的エクスプレッション)ができないことです。 コンパイルブロック内で他のSOPのデータを要するSOPは、クック中ではなく クック前に データを静的に整理しなければなりません。
(Attribute WrangleやAttribute ExpressionなどのVEXベースのノードの場合は若干異なります。VEXノードでは、VEX SOPは必要に応じて入力を試して評価することが非常に効率悪いために、常にすべての入力を評価するようになっているので、point(0, …)
はVEXで動作します。)
この回避策は、ノードに Spare入力 を追加し、参照したいノードの入力を指すようにすることです。 これで、ノードパスを使用せずにSpare入力の番号を使用することができます。 Spare入力は、コンパイルブロックを実行する前に 事前クック されます。これによって、複数スレッドがロックを気にせずに事前クックされたジオメトリを参照することができます。
Tip
ノードパス文字列(例えば、npoints("/obj/sphere1")
)を引数として受け取るエクスプレッション関数に関しては、代わりに整数を代入(例えば、npoints(-1)
)して入力を参照することができます。
To... | Do this |
---|---|
Spare入力を使って他のノードを参照する |
|
ヒントとメモ ¶
-
Spare入力は、(Wrangleノードに付いている4つの直接入力を越えて)Wrangleノードでさらにジオメトリ入力を参照するのにも役立ちます。
-
コンパイルブロック内のノードにディスプレイフラグを付けた場合、そのネットワークは、そのノードまでを(コンパイルせずに)普通にクックします。コンパイルするには、コンパイルブロックのEndノード上またはその後のノードに対してディスプレイフラグを付けなければなりません。
-
バッジを有効にすることで、コンパイルブロックで 使用できない ノードを確認することができます。
ネットワークエディタで、 View ▸ Display Options を選択するか、Dを押します。 Context Specific Badges タブで、 Non-compilable SOP Badge を Normal または Large に設定します。 コンパイルブロック内で 使用することができない ノードがバッジでマークされます。
トラブルシューティング ¶
No support for compiling this node type
多くのSOPノードタイプは、コンパイルブロックで動作するようにまだ変換が終わっていません。ネットワークエディタ内でバッジを有効にしてコンパイル不可のノードを確認するには、上記のtipsを参照してください。
コンパイルブロックで使用したいノードがまだ変換されていないようでしたら、私たちに知らせてください。そのノードの変換を優先するかどうか私たちの判断の参考にさせていただきます。
Attempt to internally reference a compiled node
コンパイルブロック内のノードを名前で参照することができません。代わりに、Spare入力を使用して、そのSpare入力番号を使ってノードを参照してください。詳細はSpare入力を参照してください。
Violation of strict nesting of blocks. Incompatible For Block Begin encountered while processing Block End. A Block Begin in Fetch Input mode may be needed
ブロックの入れ子化を参照してください。このエラーメッセージで触れられているノードを見て、コンパイルブロック/ループのBeginノード以外の何かのノードにワイヤーが横断してしまっていないか確認します。
この問題を解決するには、ループ/コンパイルブロックのBeginノードをその入力ワイヤーに追加してください。ループのBeginノードに関しては、その入力を使用したいだけであれば、 Method を Fetch Input に設定します。
See also |