🔖

【Houdini】アニメーションするツタの作成

2022/04/13に公開

Houdiniを利用して、以下のようなアニメーションするツタを作成してみました。
https://www.youtube.com/watch?v=sJC0BB6g3OU

今回はこちらの作成フローに関しまして、簡単に共有できたらと思います。
今回使用しているファイルは「IVYPOP」です(※テクスチャはありません)
https://github.com/Kuru-teo/HoudiniCollection/blob/master/IVYPOP/POPIvy_note.hiplc

【構想】

制作にあたって、最初に以下のような構想を持ちました。
この構想を念頭に置いて、色々こねこねしていきます。

【制作のおおまかな流れ】

ざっくりな流れは以下の通りです。

  1. [IVY_CURVE] popを利用してツタのカーブを作成
  2. [IVY_LEAF] 葉っぱの作成
  3. [IVY_MESH] カーブから成長するツタの茎や葉を作成
  4. レンダリング

1.[IVY_CURVE] popを利用してツタのカーブを作成

今回、成長するツタの軌道を制作するために、パーティクルのシミュレーションの結果をそのまま使用するという方法を採りました。そのためにまず、popnetで使用するvelocity fieldを作成します。

大体こんな感じで動いてほしいという形をメッシュで作成[図A]し、そこからベースカーブを作成[(図B)]した後、ベースカーブを基準にvelocityで指定空間を満たすという手順で行います。[(図C)]


↓volume wrangle内でtangentuをvに変換

int pt = nearpoint(1,@P);
v@vel = point(1,'tangentu',pt);

カーブからvolumeの中をvelocityで満たす方法は、HoudiniのTips紹介サイトの方法を活用しました。余談となりますが素晴らしいサイトですので、是非学習の参考にしてみてください。
https://www.tokeru.com/cgwiki/index.php?title=HoudiniVolumes

次にpopの処理をみていきます
pop network内では主に以下のことをしています。

➀メッシュに近づくにつれてparticleに対してノイズを加える

ターゲットメッシュへの接近はSDFを利用することで実現しました。SDFとは各ボクセルに表面までの距離が入ったボリュームデータです。ターゲットとなるメッシュをSDFに変換し、このボリュームデータをパーティクルに転送することによってターゲットメッシュまでの距離を取得します。

↓イメージ図↓ 各ボクセル位置(黄色)からの距離(赤矢印)

少しわかりづらいですが可視化すると図のようになります。表面に近いところは距離が0、色に置き換えると黒くなっていることがわかりますね。

➁パーティクルがメッシュに衝突すると、メッシュに張り付く

こちらは単純にsolverで実現しています。popcollisionbehaviorでhitしたパーティクルを識別し、rayでターゲットメッシュに貼り付けておきます。

以上のような処理を経てパーティクルの動きが計算できたら、あとは動きの軌道をカーブに変換してツタ用のカーブは完成です。左がそのままのカーブですが、ノイズなどで簡単にカスタマイズするのもよいかもしれません(右)

[IVY_LEAF] 葉っぱの作成

アニメーションに関してはbend等で適当に揺れる葉のオブジェクトを作成しました。作成したジオメトリは一旦キャッシュをとり、[IVY_MESH]にてfile sopで読み込みます。その際、packed primitiveとしてロードします。packed primitiveの理由としましては 後述いたしますがintrinsicsを使用するためです。

[IVY_MESH] カーブから成長するツタの茎や葉を作成

カーブの成長アニメーションは お決まりのcarveノードを使用します。この際、成長するカーブの先端からポイント番号0が並びますので、ptnumの0~10でグラデーションというようにしておけば先のとがったツタを作成できます。

次に葉の成長に合わせて葉を生やします。仕組みとしては以下のような感じです。

ポイントとなるのはアニメーションがオフセットしていくために、トリガーがオンになってからの時間経過をそれぞれのポイントに付与してやることです。(トリガーがオンになると白くなる様子↓)
https://vimeo.com/569369005?embedded=true&source=vimeo_logo&owner=108352501

トリガーがオンになったら(ここではCdX >= 0.05)、@Timeincでフレームごとの時間を毎フレーム足していきます。これにより各ポイントでの時間経過を取得します。(毎フレームの処理はsolver Sop)

packed primitiveでは”index”というアニメーションのフレームに対応したアトリビュートがあるので、setprimintrinsic()関数で値を渡します。
https://www.sidefx.com/ja/docs/houdini/vex/functions/setprimintrinsic.html


※ちなみに、loop処理の時に葉もはやしてしまえばよいのでは?と思うかもしれませんがforeachの中でsolverやdop networkを使用することはできませので、solverを使用する葉の処理は最後にまとめて行っています。

レンダリング

chopでいい感じにゆらしたりカーブに沿って動かして撮影したら完成です。

Discussion