今回は、Pyro Solverを用いた焦げの表現を紹介します。

記事の目次

    Temperatureの利用方法

    今回は、Pyroでつくり出されるTemperatureのFieldを使って、ジオメトリにAttributeを作成し、それを用いて焦げていく様子を表現してみたいと思います。Pyroを用いること自体は、そこまで今回は重要なポイントではないのですが、せっかくなのでPyroの基本的な使い方をおさらいしつつ、SOPベースでの焦げをどのようにして表現するか検証します。また、二次的な焦げから発生する煙なども含め、トータルでの反応をどのように表現するかも併せて検証していきます。

    Houdiniでは、単純なシミュレーションを組み合わせることで、より複雑な表現が可能になります。それはシミュレーションだけによるものではなく、SOPなどを駆使した前後処理によるところが非常に大きいです。今回の焦げる様子に関しても、基本的にはSOPをベースとした処理によるもので、その基軸に対してシミュレーションが肉付けをしていくというながれになっています。どうしても、こういったエフェクティブな内容だと、シミュレーションに目が行きがちになりますが、Houdiniにおいて重要なのはSOPでの準備と後処理だと言えます。

    今回のHoudiniプロジェクトデータはこちら

    01 Burner Sim

    バーナーのシミュレーションを行います。

    ベースメッシュ【A】【1】を準備して、それに対してCollision Source SOP【B】でGeometryとSDFへ変換します【2】

    火元となる筒を準備し【C】、それを移動させられるようにします【D】。同じくCollision Source SOP【E】で準備します。この筒の内部に火種となるジオメトリを作成し【F】、Pyro Source SOP【G】を用いて燃焼用に"burn"【3】と"temperature"【4】を作成します。

    そのPointにPoint Velocity SOP【H】を使って、バーナーの勢いとなるVelocityを作成します【5】。次に、Volume Rasterize Attribute SOP【I】により、PointのAttributeからVolumeを作成します【6】。これでシミュレーションの下準備が完了です。

    Dopnet【J】を作成し、内部にPyroのフローを組んでいきます。

    シミュレーション後は、Object Merge SOP【K】で、DOPからFieldを読み込みます【7】。DOP I/Oなどでも同じことが行えます。最後にキャッシュを取り【L】完了です。

    Collisionを準備します。Ground Plane【M】を作成し、地面とします。続いて、Static Objectでベースのジオメトリ【N】と火元のジオメトリ【O】を作成します。火元のジオメトリは動く想定なので、Use Deforming Geometryをアクティブにしておきます。それぞれVolume SampleでCollisionの設定を行い、Proxy Volumeに対してCollision Source SOPで作成したSDFを読み込みます。

    続いて、Pyroの設定を行います。今回はSparseを使ったシミュレーションにします。Smoke ObjectをSparseで作成します【P】。Voxel Sizeを適度に調整しておきます。Pyro Solverも同じくSparseで作成します【Q】。Volume Source【R】で、SOPからSourceとなるVolumeを読み込みます。

    今回はSparseを使用するため、Enlarge Fields to Contain Sources【8】をアクティブにします。これは、Sparseを使用する場合、TargetとなるFieldがSourceを包括する必要があるためです。

    また、それぞれのFieldを読み込み、Targetへ追加します。今回は燃焼を行うため、"burn"を"flame"へ【9】、"temperature"は"temperature"へ【10】、"v"は"vel"へ【11】それぞれのOperationで追加します。また、燃焼の終息をアニメーションさせます【12】

    今回のシミュレーションは高速で発生する炎なので、その勢いをある程度フォローできるように、Pyro SolverのMax Substeps【13】を高く設定しています。最終的にはモーションブラーなどで多少の誤魔化しも効きますが、その元となる素材にある程度のディテールは必要になりますので、シミュレーションコストと相談しつつ確定します。

    これでバーナーのシミュレーションの完了です【14】

    02 Burnt Solve

    焦げのシミュレーションを作成します。

    シミュレーションのキャッシュを使って、ジオメトリに焦げのAttributeを作成していきます。まず、"temperature"のFieldのみをBlast SOP【A】で抜き出します。そこからAttribute from Volume SOP【B】を用いて、ジオメトリにAttributeを作成します【1】

    このとき、どういった数値が作成されているかを確認して、数値の調整を必要に応じて行います。Attribute Copy SOP【C】を使って、"temperature"のAttributeを"burnt"というAttributeにDuplicateします。今回は、加熱と焦げを別のAttributeとして作成していきたいと思います。Attribute Blur SOP【D】でそれぞれのAttriuteをぼかします。これらに対しSolver SOP【E】を適用し、時間軸で広がっていくような処理を行います。

    別途、後述するSmokeの作成のために、"vel"のFieldを抜き出し【F】、VDBに変換しておきます【G】

    最後にジオメトリのキャッシュをとり完了です【H】

    Solver SOP内では、インプットされたままの情報【I】と計算された情報【J】を使って、時間軸で情報が積み上げられていく様子をシミュレーションしていきます。

    まず、Switch SOP【K】で、最初のフレームでインプットが切り替わるようにします【2】

    次に、"temperature"の拡散を処理します。Attribute Blur SOP【L】でぼかしたAttributeを用いて、Wrangle【M】によって少しだけ温度が周りに拡散する様子を計算します【3】

    このとき、WrangleのInput2をPrev_Frame【J】にすると、さらにどんどんと拡散しますが、今回はそこまではしていません。"temperature"をさらに少しだけぼかします【N】。必要であれば、"burnt"もぼかします【O】

    次に、Wrangle【P】を使って、"temperature"と"burnt"が時間軸で蓄積されていく様子を計算します【4】。"temperature"には係数を乗算し、徐々に冷めていく様子を再現しています【5】。"burnt"はそのまま蓄積の計算です【6】

    03 Smoke Sim

    ジオメトリのキャッシュから、"temperature"のAttributeをVOP【A】で調整し、輪郭にエリアのAttributeを作成します。そのエリアに対してScatter SOP【B】でPointを作成します【1】

    Attributeが転送されていない場合、Scatter SOPのエリア指定が効かないので、Attributeが0の場合はDelete SOP【C】でPointを削除します。また、余分なAttributeをAttribute Delete SOP【D】で削除し、Pyro Source SOP【E】でSmokeのセットアップをします。Attribute Noise SOP【F】でDensityにノイズを追加し、Volume Rasterize Attribute SOP【G】でDensityとTemperatureのVolumeを作成します。

    シミュレーションのセットアップに関して、Collision【L】やSmoke Object【M】、Pyro Solver【N】などは、前述したPyroの設定を踏襲しています。

    異なるポイントは、今回は煙なので、Volume Source【O】の設定はSmokeに準拠しているところです。また、バーナーの"vel"のFieldを読み込み、動きをマッチさせるために、Volume Sourceで"vel"をAdvectしています【2】

    Dopnet【H】を作成します。

    シミュレーション後は、Object Merge SOP【I】でFieldを読み込み、必要に応じてVDBへ変換して【J】キャッシュを取り完了です【K】

    04 Operators

    ●Pyro Solver

    今回のコアになった部分ではありませんが、重要な役割を果たしてくれたのが、Pyro Solverです。今回は、Sparseを使用していますが、非常に軽量化されたデータを使用することができて、これまででは難しかったような、大規模なシミュレーションにも手が届くようになっています。

    本連載ではあまりPyroをメインとした解説は行なっていませんが、いずれそのようなフルイドシミュレーションメインの解説も取り上げたいと思います。 従来のPyroと大きく異なるのがVolumeのもたせ方で、Sparseの場合は非連続したVoxelで構築することができると言う点です。

    これまでは、必ず直方体である必要があったSmoke Objectも、必ずしもその限りではない状態でシミュレーションできるということです。 これによって、空白だったVoxelを節約することが可能になり、従来より無駄の無い計算で低コストになったというわけです。

    Houdiniは今やエフェクトの世界ではスタンダードなツールとなりました。そういった状況もあり、今後の進化はさらに優れたものになると予想されます。Pyroはその中でも重要なアイテムなので、これを期に、研究をしてみてください。

    TEXT_秋元純一 / Junichi Akimoto
    EDIT_小村仁美 / Hitomi Komura(CGWORLD)