kick the base

Houdiniと、CG技術と、日々のこと。

Houdini: モデリングと時間と。

もうアドベントカレンダーの季節とか嘘でしょう…?(記憶喪失)

気を取り直して皆さんいかがお過ごしでしょう。

今年もおかげさまでゲーム・ノンゲームを問わず難度の高いプロジェクトに参画させていただくことが多く、日々充実した毎日を送っていますが、技術発信の頻度が落ちてしまっているのがアレですね。反省。

というわけで今回はTwitterで見かけたHoudiniの質問に対する僕なりの解法が非常にHoudiniらしいなーと思ったので初心者の皆さんにご紹介できればと思ったのでそんな話です。内容は難しくないですが、パラダイムシフトが大切ですよっていうやつです。

本記事はHoudini Apprentice アドベントカレンダー2023 8日目の記事です。

目次

お題

TLで見かけた質問でかつポスト主が自己解決されたようで、現在は該当ツイートはないと思うのでうろ覚えですが「For-Loop with Feedbackの結果をループ処理回数ごとにマージしたい」といったもの。

前提

HoudiniのSOPレベルのループ処理には「累積型(Feedback)」と「個別型(Merge)」に分類され、Gather Methodパラメータによって指定しますが、その中身の解説は今回はしません。「For-Loopの仕組みがよくわからない」「Wrangleってやつとは仕組み違うの?」みたいな疑問がある方はどこかのタイミングで僕の初心者向け講座などを受講いただければゼロから丁寧に解説します。

また、アトリビュートはなにか、関数の使い方はどうするのかなどの基本的な内容もここでは割愛させていただきます。(疑問がある方はどこかのタイミングで僕の初心者向け講座などを…以下略)

今回のケースについてものすごく簡単に書くと、累積型(Feedback)で処理してるネットワークなので、処理が終わる → その結果を持ち越してBlock Beginに戻る → 処理が終わる → その結果を持ち越してBlock Beginに戻る → ... と処理を積み重ねていくので、ひとつのジオメトリを何回もゴニョゴニョするという処理になります。

これをループ回数ごとにジオメトリが取り置きされて最後にマージされるような処理に変更したいということですね。

データ配布

記事で使用したシーンはこちらからダウンロードできます。

  • Windows10
  • Houdini 19.5.640

実装

ここから実装のお話に入っていきます。まずFor-Loop with Feedbackの挙動がわかりやすい簡単な例を考えましょう。今回は「上流からジオメトリが渡ってきた時、Primitiveが個別に押し出され、その押し出し量は各々ランダムなzscaleアトリビュートによって決定される」というものを用意しました。

言葉にするとちょっと難しそうに見えるかもしれませんが、GIFアニメを用意したのでそちらをご覧ください。イメージしやすいかと思います。

Feedbackの挙動

ループ回数を経るごとに面が押し出され、全体的にはどんどん大きくなっていくような印象になります。

上記までを処理Aとするとそれを改造したのが処理Bです。下図のようにループ回数ごとにその時の結果がマージされていますね。※ わかりやすく横に並べていますが、実際は同じ位置に生成されたものがマージされます

処理B

以下に解説を進めていきましょう。

処理A

処理A

ネットワークは画像の通りで、特に難しいことはしていません。repeat_end1ノードのiterationパラメータを増減させてみればループ総数を指定できます。ループ処理の流れは簡単に以下のとおりです。

  1. SortSOP: プリミティブナンバーをランダムに並べ替え
  2. 1で並べ替えたプリミティブナンバーをシードにzscaleアトリビュートを作成、ランダムの最大最小は良き塩梅で調整
  3. Poly ExtrudeSOPで面を個別に押し出し、移動距離にLocal Attributeszscaleを指定しています

大切なことは1~3で変更がかかったジオメトリがその結果のままBlock Beginに持ち越され、また処理を繰り返されるということですね。これが蓄積型と呼ばれるゆえんです。

処理A’

処理A'

処理AのBlock BegineSOPのパラメータは変更せず(MethodFetch Feedbackのまま)、Block EndSOPGather MethodパラメータをMearge Each Iterationに変更してあげると目的は達成されます。これが最も簡単な対処法でしょう。

が、処理Bの考え方も学びがあるので見ていきましょう。

処理B

処理B

Block EndSOPGather MethodパラメータはFeedback Each Iterationに戻し、ここではiterationsの値を$F-1にしているのがポイントになります。(1を引いているのはおいておいて、時間によってループ回数が決まるのが重要です)

先程まではiterationsの値を直接バリューラダーなどで変更してループ回数の変化を見ていったと思いますが、今回はシークバーを移動するとループ回数が変化するという訳ですね。フレームが3なら2回ループ、フレームが7なら6回ループという具合です。

続けてTrailSOPで現フレーム分のジオメトリをコピーしています。ここも重要です。

最後にTimeShiftSOPで最終的なジオメトリの個数を決め打ちします。これをしないとシークバーの影響をずっと受けてしまうので、その対応になります。

振り返ってみると今回の考え方で重要なのはループの回数をフレームに依存させることと、フレームごとのジオメトリをコピーするという2つの合わせ技で「ループのマージ」を実現しているところです。

通常のDCCツールではアニメーションはアニメーション、フレーム数はフレーム数、モデリングはモデリングと別々のモノですが、Houdiniではそれらはすべて利用可能なデータであるということがわかりやすい例かなと思います。

それでは皆さん来年も素敵なHoudiniライフを!

ではでは。