HoudiniVolumes

提供: Houdini CGWIKI Jp
移動先:案内検索

ボリュームはプリミティブです

初めての方は、この事に若干戸惑うと思いますので説明しておきます。 ボリュームはプリミティブの一つであり、同様にポイントもプリミティブ、プリミティブ球もプリミティブです。 例えばポリゴンメッシュとは違って、サブコンポーネントまでドリルダウン(掘り下げる)することができないことを意味します。 つまり、Geometry Spreadsheetを開いて個々のボクセルの値を確認することができません。

ボリューム内で起きている事を確認するための他のツール(Volume Slice SOP,Volume Visualization SOP,Volume Trail SOPなど)が用意されていますが、 例えば、最終的に400x400x400のボクセルボリュームとプリミティブ球を結合して、その結果を調べてみると、ボリュームと球の2個のプリミティブになっていることが確認できることでしょう。

Houdiniは2つのタイプのボリュームに対応しており、1つが独自のボリューム形式、もう1つがVDBです。これらのボリュームはポリゴンまたはNURBSと同様にプリミティブとして扱われ、ノードを中クリックして確認してみると、 '1 VDB'または'1 Volume'のように表示されることでしょう。

VDBとは?

VDBについて最も簡単に説明すると、ボリューム版のAlembicのようなものです。 VDBはオープンソースの標準化されたフォーマットなので、HoudiniからVDBをエクスポートして、それをMayaに読み込んでVrayでレンダリングすることができたりします。 VDBはいくつもの企業(有名所ではDreamworks, Double Negative, SideFx)から支持されている良いフォーマットです。

Alembicは主にファイルフォーマットとして使われていて、Alembicファイルを操作/表示するための便利なサンプルツールがありますがVDBはそれ以上に便利です。 VDBツールキットによって、ボリュームを保存したり、ボリュームを操作するためのたくさんのアルゴリズムを利用することができます。

VDBの最も面白い特徴の1つは、空っぽのボクセルに対して無駄にストレージを消費しないことです。そのため、VDBのストレージ容量は他のフォーマットと比べて小さいです。

VDBストレージフォーマットは、Houdiniではプリミティブ(おかしなことに'VDBプリミティブ'という名前)として表現されていて、これを操作するツールこそが名前の頭または後ろにVDBが付いたSOPsです。

論文に記述されているVDBという名前の由来は、"...Volumetric, Dynamic grid that shares several characteristics with B+ trees.(いくつもの特性をBツリーと共有した動的ボリュームグリッド)"から来ています。

詳細: http://www.openvdb.org/about/

VDBの操作チュートリアル

VDBのすばらしい機能の紹介はOpenVDBのサイトにもあります。そこには、VDBに関して操作して学べるように1個のHoudiniファイルになっていて、章毎にオブジェクトが分かれていて付箋がたくさん付いています。 私はこれを最近知って驚きました。これを教えてくれたODforceの人に感謝です!VDBを使用したい方はいますぐダウンロードしてください。

http://www.openvdb.org/download/

http://www.openvdb.org/download/houdini_examples.hip.zip

VDB vs Houdiniボリューム

Houdini独自のボリュームフォーマットは、VDBが誕生する前から使われていたので、そのボリュームを扱うためのノードがたくさんあります(Tabメニューで'volume'とタイプすることで、それらのSOPsを調べることができます)。 VDBにもそれ用のノード群があります(ノード名の頭または後ろにVDBが付いています)。

実質的にVDBsはネイティブのHoudiniボリュームよりも小さい(一般的には50%節約)です。そして、VDB SOPsの方がネイティブのHoudiniボリュームSOPsよりも速くて、面白い機能が多いです。

(他のアプリケーションにエクスポートするために)拡張子が.vdbのファイルフォーマットが存在しますが、容量を節約するためにわざわざ.vdbファイルに書き出す必要はなく、Houdini内でVDBプリミティブを使用するだけでも十分です。 HoudiniボリュームプリミティブはいつでもVDBプリミティブに変換することができます。これは、単にConvert VDB SOPを接続して、そのモードをVDBにすればよいだけです。 そのノードを中クリックすると、VolumeプリミティブがVDBに置換されたことを確認できることでしょう。 これをHoudiniジオメトリの他のピースと同様に.bgeoにキャッシュ化することができるようになり、変換しなかった時と比べてサイズが非常に小さくなります。

素晴らしいのが、多くのコアのHoudiniボリュームツールがVDBプリミティブも扱えるように更新されていることです。 例えば、Volume VOPsとVolume WranglesはどちらもVDBを扱うことができます。つまり、いつでもVDBを安心して使用することができるので、必要に応じて一時的にVDBをネイティブボリュームに変換し、そして変換を戻すことが容易であるということです。

詳細: https://www.sidefx.com/ja/docs/houdini16.5/model/volumes

スカラーボリュームとベクトルボリューム

例えば、雲の表現に使用するボリュームはボクセル毎にdensity(密度)の単一値を保存すれば良いだけです。 densityが0のボクセルは完全に透明で、densityが1のボクセルは不透明です。例えば、Cloud SOPは内部的にノイズ関数を使用することで目的の雲の形状になるようにdensityを調整します。

雲の中でカラーが変化するように保存したいのであれば、赤/緑/青のコンポーネントを保存する必要があります。つまり、このような情報を保存するためにはベクトルボリューム(またはベクトルフィールド。ドキュメントやフォーラムではボリュームのことをフィールドと呼んでいることを目にすることが多いかと思います)が必要です。

ベクトルフィールドは主にVelocity(速度ベクトル)によく使用されます。Houdiniの慣例では、Velocityボリュームの名前は'vel'です。 ボリューム内の各ボクセルには方向が保存されています。Pyro Solverは、このVelocityフィールドを使ってdensityを移してその動きを表現します。 Pyroシミュレーションの他のプロパティによってVelocityフィールド自体を変更することができるので、上方へ巻きながら昇るキノコ雲やdensityを渦巻くノイズを取得することができます。

注目して欲しい事は、ネイティブのHoudiniベクトルボリュームとVDBベクトルボリュームの違いです。 実際には内部的にHoudiniはベクトルボリュームフォーマットを持っておらず、代わりに3つのスカラーボリュームを生成し、それらのボリュームを単一要素として扱います。 densityとvelocityを使用する標準の煙セットアップは、density, vel.x, vel.y, vel.zの4つのボリュームプリミティブを持ちます。

VDBはベクトルボリュームに対応しているので、同じ煙セットアップでもdensityとvelの2つのVDBプリミティブを持ちます。

ボリュームは、通常のジオメトリのアトリビュートの扱い方とほぼ逆であることに注意してください。

  • グリッドが単一ジオメトリでも、そのグリッド上の各ポイントには多くのアトリビュート(N, Cd, id, foo, myattrなど)を持たせることができます
  • ボリュームプリミティブは1個のアトリビュートしか含めることができないので、代わりに複数のボリュームを作成し、各ボリュームに対して1個のアトリビュート(density, vel, fuelなど)を格納します。


Houdiniの一部のツールでは、この違いに対応していて、すべてのボリュームをまとめて単一要素として扱います。 他のツールでは、例えば、densityとvelocityと一緒にCdフィールドも変更するようにPyro Solverに明示的に伝える必要があります(この例を後述しています)。

ほとんどの場合、Houdiniに必要なフィールドがデフォルトで扱うので、実際に手動でフィールドを指定することはあまりないです。

SDF

Volume compare.jpg

ボリューム(またはVDB)は、霧、炎といった不明確な形状を表現したり、ソリッドサーフェス(中身の詰まった形状)を表現することができます。 ソリッドサーフェスを表現する時は、表面を境に内側/外側を意味したその表面上の最近接点までの距離が各ボクセルに格納されます。 これらの値には(1だけではなく表面までの距離の1.42などの)浮動小数点が入るので、入力ジオメトリを非常に良い近似値で表現することができます。 ボクセルが表面の内側/外側のどちらにあるのか表現するために、この値はプラスまたはマイナスになります。プラスが外側、マイナスが内側です。 これを可視化すると、形状の輪郭の勾配が0で、その内側と外側に向かって勾配が滑らかに広がったように見えます。このボリュームのことをSigned Distance Field(符号付き距離フィールド)またはSDFと言います。

Viz sdf.gif

プラスの値が赤から黄、マイナスの値が濃い青から明るい青です。


これは色々な事に役立ちます。確実にSDFを生成することができれば(もちろんHoudiniを使えばできます)、シミュレーション用の衝突ジオメトリをうまく生成することができます。 パーティクルまたはRBDオブジェクトはSDFを非常に迅速にサンプリングすることができ、そのSDFの符号がマイナスならそれは形状内側であると認識されます。 そして、パーティクルまたはRBDオブジェクトはSDFの勾配を測定することができるので、SDFと交差しないように押し出す距離を正確に決定することができます。

SDFを受け取ってポリゴンに変換すると、そのポリゴンは均等にメッシュ化された閉じたサーフェスになります。その表面を膨張または収縮させることができ、SDFを組み合わせて非常にうまくブール演算させることができるので、色々な場面で役立ちます。

Poly mesh vdb.jpg

Houdiniでは、ポリゴンからSDFを生成する方法が2つあります。その1つがネイティブHoudiniボリュームを使った方法(SDFボリュームモードのIsoOffset SOP)、もう1つがVDBを使った方法(VDB from Polygons SOP)です。 私のテストでは、詳細なジオメトリを生成するのにVDBの方が非常に速かったです。

Houdiniは、SDFフィールドが0の箇所でボクセル毎にスプライトを使ってSDFボリュームを可視化します。 これは、SDFの勾配を使ってスプライトの法線を向けた表示になっているので、そのスプライトがライティングに反応します。

ボリュームデータを確認する方法

Sdf visualise.jpg

シーンをダウンロード: File:vis_volume.hip

ボリュームまたはVDBは独自のプリミティブタイプとして扱われているので、そのボクセルデータをGeometry Spreadsheetから調べることができません。 調べようとしても、各ボリュームのプリミティブ番号が表示されているだけです。

代わりに、ビューポート内で可視化ツールを使用してください。 Volume Slice SOPは、ボクセルデータをカラーランプにマッピングした2Dスライスを表示することができます。 Volume Trail SOPは、ボリューム内の方向、つまり、ボリューム内の勾配に沿ってラインを表示することができます。

サンプルのhipは、2通りの方法でボリュームを扱った例が示されており、2通りの方法で勾配を計算しており、1つが'volumegradient'VEX関数を使用し、もう1つが'VDB Analysis' SOPを使用しています。 VDBノードは、通常のHoudiniノードとは若干違って表示されていますが、非常に強力で非常に高速です。

Volumes, SDFs, Trails

Vol trails.gif

シーンをダウンロード: File:volume_trails_V01.hip

渦巻くラインを生成する面白いVIMEOチュートリアル( https://vimeo.com/134057856 )、ノイズからトレースラインを生成する方法を投稿したodforce( http://forums.odforce.net/topic/23535-noise-how-to-convert-into-line/ )を見ました。 これは、それら2つの内容を組み合わせています。Volume Trail SOPを使ってボリューム内のフィールドを可視化しているので、セットアップしたボリュームがあれば、これを使って色々な事を試すことができます。

ここでは、形状を受け取って、そこからSDF(Signed Distance Field)を生成しています。 これは、各ボクセルに表面上の最近接ポイントまでの距離が入ったボリュームです。表面上のボクセル値は0で、表面より外側のボクセル値はプラスの値、表面より内側のボクセル値はマイナスの値です。 これは、他のオブジェクトとの衝突を確認するのに非常に便利です(ここに2DでSDFを可視化する素晴らしいshadertoyデモを載せておきます: https://www.shadertoy.com/view/ltBGzK )

このシーンでは、各ボクセルにベクトル値を格納可能な'vel'という名前のボリューム(ボリューム内にベクトル値を格納するHoudini標準ボリューム)を作成しました。 そして、SDFを使ってvelフィールドをクリップし、次に表面下0.1範囲内のボクセルのみを残し、残りのボクセルを削除しています。

そして、そのボリュームにカールノイズを適用して、そのvelフィールドがボリューム内で面白くニョロニョロと渦巻くようになっています。 それをVolume Trail SOPに接続することで、面白いラインを生成しています。

このラインが豚の表面を沿うと同時に、その表面から上下に少し揺れようとします。 それらのラインを表面上に直接引っ付けさせるために、(クリップした分の交差問題も考慮して)豚を若干太らせたコピー上にそれらのラインを投影しています。

おそらく、これがSDFから直接カールノイズを生成する方法で、その結果のラインは表面上に引っ付きます。Ray SOPを使えば簡単にそれらのラインを表面上に寝かせることができます。 :)

ボリュームの磁力線

Vdb maglines.gif

シーンをダウンロード: File:magnetic_lines_vdb.hipnc

磁力線をセットアップする方法を説明したこの投稿( http://pepefx.blogspot.com.au/2015/08/how-to-create-magnetic-vector-field-in.html )を見つけました。 非常に疲れている時に一度これに挑戦し、1ヶ月後に再び彼の説明と彼の天才的なVEXを見ずに同様のエフェクトができるか挑戦しました。

このセットアップで面白い事が2つあります:

  • ポリゴンからVDBを作成します。具体的には、1つのポリゴンからdensityとvelのVDBを同時に作成します。VDB from Polygons SOPには、ROPで言うAOV/画像平面の生成と同様に複数生成機能があります。Surface Attributesをクリックして、新しくアトリビュートを追加し、ソースとなるアトリビュート(Velocityならv)とマッピング先のVDBの種類(ベクトル)を指定します。
  • VDB Combine SOPでVDBを組み合わせます。私はプラスとマイナスのVDBを用意してから、それらのVDBを'add'モードで組み合わせました。これによって、1ステップでそれらのポリゴン形状の結合とVDB化が行なわれました。これは非常に効率が良いです。もっと練習します?


ここで得られた結果は科学的で好きではないですが、可愛いく見えます。 正直なところ、このセットアップが動作するとは思ってもみなかったです。マイナスとプラスのVelocityフィールドを作成するという発想はあまりにも単純すぎてVolume Trail SOPが動作するとは思っていなかったのですが、ここでは動いています。 これらのラインとカラーは、私がVolume TrailとPoint Wrangleでよく使っているものです。

ボリュームとカールノイズによる渦巻いた線もしくは虫

Pig worms.gif

シーンをダウンロード: File:vol_worms_curlnoise.hipnc

線を渦巻かせる方法は他にもありますが、私はこれが非常に効率的だと思っています。 Raph氏のvery cool experiment on vimeoを見て、それがどのように実現されているのか興味を持ちました。 彼は私よりも2メートル先を進んでいますが、本来の私はプライドが高かったので彼に質問できませんでした。暫くの間、私はこれに手こずっていました。

私はPyroを試行錯誤した上でボリュームとVelocityフィールドの作り方を知り、Volume Trail SOPはカッコいい結果を出せると感じました。 SDFを入力に使用する方法を知ってからVolume SOPでカールノイズを使用してきました。 Volume Trail SOPの試行錯誤を始めてから、驚いたことに、それによって私が欲しかったエフェクトを正確に再現することができ、ヘルプドキュメントを読んで確信しました。 例えば、川の中に岩を配置する感じで、これは、カールノイズによってSDF周辺を流れさせることができます。

以下はそのワークフローです:

  1. 形状を受け取ります(この場合では安定の豚さんを使いました)。
  2. その境界を取得して、そこからvel fog VDBを作成します。
  3. さらに豚さんからSDFを作成します。
  4. Volume SOP内でカールノイズを使用し、そのカールノイズの入力のCollision SDFにそのSDFを接続することで'そのSDFを回避'させて、スライダを調整してカールノイズを好みに合わせます。
  5. VDBの値がマイナス値(つまり、豚さんの形状の内側)かどうかをテストし、内側の値を1、外側の値を0にします。
  6. この結果にカールノイズを乗算して、豚さんの外側のすべてのvelを0に設定します。これで、カールノイズは表面沿い、または、豚さんボリュームの内側に流れるようになりました。
  7. 豚さんの表面上にポイントをばら撒き、Volume Trail SOPでカッコいいラインを生成します。
  8. @widthを使ってカーブを直接レンダリングするか、または、Polywire SOPを使ってポリゴンチューブを生成します。


もちろん@widthを定義したカーブの方が効率的ですが、それによる不具合があり、OpenGLによって変なスパイクやポップが発生するので、私のフリップブックキャプチャではPolywire SOPを使っています。 カールノイズの入力に時間を与えているのでラインが踊ります。

以下は、イカ蟹に同じエフェクトを適用しました。さらにSDF値でカラーをグラデーションさせています。表面付近の値からホワイト、赤、ピンク、ブルーになっています。お好みに応じて光沢を付けています。

Squab viscera small.jpg

シーンをダウンロード: File:vol_worms_curlnoise_v02.hipnc


効率良くジオメトリをVelocityボリュームに変換する

'VDB from Polygons'ノードは、メッシュをSDFまたはフォグにうまく変換することができ、メッシュに@vを含めればVelocityフィールドも作成することができます。

例えば、豚さんがいて、そこにポイント法線を与えて、Wrangleで@v = cross(@N,{0,1,0});を記述して渦巻いた@vを作成してから、'VDB from Polygons'を使うと、densityフィールドだけでなく、@vから@velフィールドも作成することができます(私の場合、さらに散乱ポイントを追加し、Volume Trail SOPを使って、その渦巻きフィールドを可視化しています):

Vel field watertight.gif

メッシュが閉じていない場合、VDB Convert SOPが誤認識してしまうので、非常に密度の濃いサンプリング設定をするか、または、Extrudeか何かを使って無理やり閉じたジオメトリを作成する必要があります。

この例では、豚さんを、法線とVelocityを持ったカーブに入れ替えました。そうすると、VDB from Polygonsノードがdensityフィールドを作成できなくなるので、全体的に壊れます:

Vel field curve bad.gif

ここで本当に必要な事は、一般的なdensityフォグを作成できる事と、カーブの@vアトリビュートをボリュームの@velアトリビュートに転送できる事です。これは、2,3個のノード(Volume from Attribute, Volume Velocity, Volume Velocity from Curvesなど)で行なうことができますが、残念なことに、どのノードもVDBではなく通常のHoudiniボリュームしか扱えません。つまり、変換をしてから処理をしてまた変換を戻すので面倒です。

Volume Wrangleを使用する方が得策です:

Vel field curve good.gif

以下が上記のgifで使われているコードです:

  1. まず最初に密度を格納するための箱が必要になるので、Bound SOPを使って豚さんからボックスを作成し、それをVDB from Polygonsに接続します。
  2. これまで、VDB from Polygonsノードを使って@vからvelフィールドを作成してきましたが、このボックスにはvelフィールドがありません。このVDB from PolygonsノードのAttributeパラメータをpoint.Pに変更します。
  3. これで、velフィールドには実際には@Pが保存されるようになりましたが、これは単なるプレースホルダーです。
  4. このVDB from PolygonsノードにVolume Wrangle SOPを接続し、次の2つの処理をします:
    1. int pt = nearpoint(1,@P); --- ボクセル毎にカーブ上の最近接ポイントを検索し、そのポイントの@ptnumを取得し、それをpt変数に格納します。
    2. v@vel = point(1,'v', pt); --- そのカーブ上のptにおける@vを読み込んで、それを現行ボクセルの@velに格納します。
  5. このVolume Wrangle SOPにVolume Trail SOPを接続して、その結果を表示します。


単に@velではなくv@velを使用していることに注目してください。@velは、Houdiniがアトリビュートのタイプを自動的に認識できる'特別な'Wrangleアトリビュートの1つではないことを知って驚きました。 忘れているかもしれませんが、この@velはfloatとして扱われます。このことが暫くの間、私を苦しませました。

これがそのシーンです: File:volume_vel_from_geo_curve.hipnc

私にこの違いを教えてくれたLuke Gravettに感謝します。

ボリュームのディスプレイスメント

Volume displacement.gif

シーンをダウンロード: File:volume_disp_example.hip

これを構築するのは非常に難しいことだと思っていたのですが、いざやってみると、実際には非常に簡単でした。 一般的には、ボクセルを小さくすればするほどボリュームの見た目が良くなりますが、ご存知の通り、これではディスク容量、メモリ、レンダリング時間が増えます。 HoudiniとMantraはボリュームのディスプレイスメントに対応していることを知っていましたが、私が見てきたどのチュートリアルも非常に複雑なことをしているように思いました。

Patreon支持者のIsaac Katzの助言のおかげで研究が進み、このsimple example by Marc Picco on the odforce forumsに辿り着きました。あなたがするべき事は、通常のポリゴンディスプレイスメントに対してシェーダをセットアップする事なので、Pを取得し、ノイズを追加し、それをディスプレイスメント出力に接続します。

上記のgifは、これによる効果を示しています。ボリュームの豚さんの初期解像度は非常に低い(豚さんの基本的な形状を取り込むのに十分な25x27x29)です。レンダリング時にディスプレイスメントを行なうことで、 これがピクセルレベルで細かくなり(また、ディスプレイスメントを駆動させるノイズが十分に細かい場合には、ズームインで拡大してもサブピクセルは細かいです)、そのレンダリング時間は非常に理に適った時間内に収まります。

下図は、Material Paletteの'basic smoke'シェーダに追加したノードです。少し混乱しそうなのは、ディスプレイスメントノードを作成する方法くらいで、出力ノードのタイプを'displacement'に変更すれば良いだけです。

Volume displacement shop network.jpg

ボリュームの変形

Volume deform.gif

シーンをダウンロード: File:volume_deform_simple.hip

ボリュームの変形は簡単なように思えますが、いざやってみると難しいことがわかるでしょう。 Pixar社のREVESのような楽々に扱える便利な内製ツールが存在しますが、部外者の私達はどうすれば良いでしょうか?

さて、これを行なう簡単な方法(Volume Lattice asset on Orboltまたはthis example by Juraj Tomori )が存在します。 どちらの方法もボリュームとのダイレクト変換をしていて、若干裏技的な方法です。消えているこのVIMEO投稿のヒントと共同作業者からのヒントから、これは、そんなに悪くなく、ある程度の高解像度ボリュームでも非常に高速に動作します。

この方法は2つの部分に分かれており、1つがVDB Visualize Tree SOPによってボリュームからポイントに変換する方法、もう1つがVolume from Attribute SOPを使った変換でボリュームに戻す方法です。

VDB Visualize Tree SOPは、ボリュームからポイントに正確に変換することができます。Active Voxelsにチェックを付けてPointsを選択し、Points with Valuesにチェックを付ければ、すべてのボクセルからポイントが抽出され、それらのポイントの@vdb_floatに密度が格納されます。

これによって、変形を適用できるポイントが用意できましたので、ここでLattice SOPを使用してポイントを変形させました。

変換してボリュームに戻すために、Bound SOPを使って、変形させたいポイントの境界ボックスを取得し、次に、VDB from Polygons SOPを使ってフォグVDBを取得し、Convert VDB SOPを使ってフォグVDBをHoudiniボリューム(私の簡単なテストでは、IsoOffset SOPを使用するよりも速かったです)に変換します。これでボリュームが用意されました。Volume from Attribute SOPを作成し、その新しいボリュームをその1番目の入力に接続し、変形させたポイントを2番目の入力に接続します。

Volume from Attribute SOPの挙動はその名前のとおり、指定したPointアトリビュートを読み込み、それをボリュームにコピーします。このノードの設定、VDB from Polyugons SOPの解像度を調整することで、詳細レベルと処理速度のバランスを取ることができます。Volume from Attribute SOPはVDBに対応していないので、通常のHoudiniボリュームに変換する必要があります。

それでもREVESが羨ましいなぁ。

さらなる学習

SmokeとPyroには長いチュートリアルがあり、このページを基礎とした多くの内容を網羅していますが、より端的に説明し、シェルフツールを使わずに煙のセットアップを構築する手順を学びます。 私は、誰もが最初にSmokeとPyroを習得するにあたって、わかりやすいチュートリアルになるようにまとめました。そのチュートリアルはここにあります: Smoke_and_Pyro