ボリュームのポスト処理



ボリュームのポスト処理、というのは端的にいうと煙とかをシムした後にどうにかするということであり、要するに変形したりとかノイズを入れたりとか部分的に削ったりとかそういうやつです。

ちょっとした変形ならfumeとかでもできますが、当方の知る限りfumeでできるのは曲げたりねじったりラティス変形（できたはず）したりで、要するにシルエットごと変えるという割と大味なやつです。
これに対してフーディニはかなり自由で、上にあげたやつは割と簡単にできます。

サンプルシーンはこちらになります。

https://www.dropbox.com/s/hv2naot9ye6t757/vol_post_manip2.hipnc?dl=0

（記事を読むのがだるい人はサンプルシーンのドロップボックスの外に出ているnullをみてください。
内容を軽く知りたい人は画面をさらっとスクロールさせてください。ジフが貼ってあるのでどういうことをやっているのかだいたいわかると思います。）



こういう機能はおそらくフーディニ移行組が見落としがちなものでそういう人たちは、fumeやmayafluidでできないものはそもそも期待しない、期待するのはその速さだけ、と考えている場合が多いような気がします。

それは少しもったいないし、この機能をを知ることで、しなくていいシムの幾らかをせずに済ますことができるのでかなりおすすめの機能だったりします。

フーディニに移行したい人は既にしていて移行していない人は移行するつもりがない人、という印象がちょっと前まであったのですが移行したくてもまだできていない人は結構いるらしいので当記事はそういう人向けです。
レベルとしては大して難しいことはやらないので中級者向けぐらいだと思います。

で、そのボリュームのポスト処理は何を使ってやるかというと　volume wrangle を使います。
というかこれ以外はほぼ使いません。なのでこの記事の表題をわかりやすくすると、


volume wrangle を使おうぜ！


という感じになります。
正確にはシムにも使うのでvolume wrangle以外にも gas wrangle も使いますが使い方はほぼ同じです。

1　static volume
--
まず基礎的なことから。

（サンプルシーンの sim内、一番左のバックドロップで囲ってあるstatic volumeの部分でやってます。）

フーディニはシムしなくてもジオメトリをボリュームにしたりできます。
なのでなんでもないジオメトリからよくわからないものをつくっていきます。
ここではシムは全くしないのでポスト処理ではないのですが気にしません。
とりあえず次のジフをみてください。
![1b.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316376/724ddbb5-a41c-e76a-c033-7967f7633efa.gif)

ここでやっているのは、

**f1** トーラスを
**f2** 粒の集合にしてから
**f3** ボリュームにして、それを
**f4** 単純に濃くしてから
**f5** ノイズ混じりに薄くして、
**f6** 斜め横に移動しようとしますが、そのままやると形状が部分的に消失してしまうので
**f7** ボリュームの有効範囲を調整した上で斜め横に移動して、
**f8** 移動をしなかったことにして渦を巻くように捻り
**f9** 奥側半分に位置的なノイズをかけてます。

シーンファイルを見れば大体わかると思うので詳しい説明はしませんがいくつか補足。
まず、

volume sample

というコマンドが使われていますが、これを使うと座標を特定してボリュームの情報を取得できます。たとえば右ちょっと上の座標の速さを持ってくるとか。
**f6**と**f7**でやっているのは

````
vector pos = v@P+.75;
f@density = volumesample(0,"density" , pos);
````

なのですが、これは現座標から0.75だけ斜め上のdensityをゲットして値をセットしているんです。
だから結果として斜め下にずれる。
プラスをしているのだから斜め上のはずでは？と考える人もいると思いますが間違ってます。
v@P+.75というのは、ボリュームを0.75だけ移動する、という意味ではなく
現座標の0.75だけ上の情報を取得する、ということなので
全座標が斜め上の情報を取得して入れ替えているのだから結果としてその分だけ斜め下にずれるんです。
**f9**でノイズをかけている時も同じ。
(わからない人は、プラスとマイナスで逆方向に移動する、とおぼえておけばいいです。)

ただ、ここで注意しなくてはいけないのは、コンテナ範囲外の情報はいかなる場合でも０として取得される、ということです。
**f6**でうまくいっていないのはそのためです。単純にボリュームの範囲をはみ出しているんです。

なのでそれを解決するためにボリュームを拡大してやる。それがf7。
だから同じことをやっているのにうまくいくのです。
ただし情報の取得先が違うので注意してください。**f6**では自分自身の情報だから

````
f@density = volumesample(0,"density" , pos);
````

になっていますがf7では元のノードから取得しているので

````
f@density = volumesample(1,"density" , pos);
````

となってます。最初の引数は　0 ではなく　1 。
流体を捻るというのは特殊なケースですが、アニメーションさせたりすると割と実戦でも使えます。
捻った後の**f9**でノイズをかけてますがここには特に解説はいらないでしょう。

2 シム後の適用 (サンプルシーンのdelete source point vol)
--
（サンプルシーンの sim内、左から二番目のバックドロップで囲ってあるdelete source point volの部分でやってます。
ここではh18で実装されたsparse solverとsop pyro solverでもテストをしてます。そのせいでちょっと整理できてない感じのツリーに。）

実のところ機能の説明は上で全て済んでいるのでここから先は実用面でどう使うかについて。

まず煙を放射状に広げたいとします。ここでやるべきは、放射状にベロシティを与える、ではありません。
そうではなく、煙を地面に向けて真下に噴射する。するとこうなります。

![2a_.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316376/fe1d5ab3-102b-9eb1-a9b9-8433bdf681b6.gif)

が、この方法だとエミッター部分が邪魔です。シルエット的にいらないのです。
なのでそのエミッター部分だけを削ります。

![2b.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316376/1b251654-d7ae-a28d-10a3-108d170db019.gif)


エミッター部分の情報を取得しその部分のデンシティをシム結果から削っています。

エミッター部分を削ったことによってシルエット的におかしい感じは薄れたと思います。(この例だとエミッターに隙間がないので広がっている感じが弱いんですが)
煙の発生部分が汚いですがこういうのはどうせモーションブラーで消えるので気にしません。

ついでですが、こういう動きをした流体にパーティクルを乗せるとこんなかんじのができます。

![2e.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316376/75df16f6-8c69-c373-6333-68dae7628c48.gif)

この例ではpop advect by volumeを使わずにwrangleで書いてます。
なぜかというと単にadvectbyvolumeが好きではないからです。

あとadv by volumeもwrangleの方法二つともボリュームの回転に対応していません。
回転後のベロシティを使ってアドベクトしたい場合は粒にした上で傾けて、その粒の情報をパーティクルに突っ込んでください。
実例を見たい人はサンプルシーンでのsim内、右から二番目のotherの左側、pop advect mixを確認してください。


3　応用2。シム内とシム後の処理（サンプルシーンのcoming smoke)
--
（サンプルシーンの sim内、一番右のバックドロップで囲ってあるcoming smokeの部分でやってます。）

まず前提として、pyroでの浮力（buoyancy) ですが、これは熱だけに反応するものなので熱がない場合は浮力は存在しません。densityに浮力はないのです。
では熱がない場合は煙を立ち昇らせることができないかというとそんなことはありません。
dop内でgas wrangleをつくり、こう打ちます。

````
v@vel.y +=1;
````

するとだいぶ駄目な感じの挙動が見られます。
これをいい感じにするためにはアドベクト感が必要ですが、アドベクト感を出すためにはdensityだけに浮力を与えます。そうするためにはこう打ちます。

````
v@vel.y +=1 * f@density ;
````

これで多少良くなりますが、この仕様だと無限に加速するので長時間のシムには耐えません。
なのでドラッグを入れます。dragノードを刺してもいいのですがこのノードの挙動とか知らないですし、当方は代わりにwrangleでやります。
gas wrangleをもう一つつくってこう打ちます。

````v@vel *= 0.98;````

これでちょっと良くなると思います。
なぜ二つにwrangleを分けるのかというとdisableするときに楽だからです。

この仕組みを使って煙がこっちに来る感じをつくってみます。

![4a.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316376/5d8d0ad7-59ab-6ad6-c7f9-425fd5a1b8a4.gif)

このままだともちろん駄目なので、ポスト処理でなんとかしていきます。

まずエミッター部分が邪魔なので消します。
![4b.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316376/a705e071-4b5d-8979-cfb7-ca17f18c8a0b.gif)

上の方が切れているのでごまかします。（横は切れてないことにします。）
本当はコンテナを拡大すべきなんですが、もうデータをつくってしまった後だしやり直すのも嫌なので別の方法でごまかします。
![4c.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316376/5819a6e8-7a3d-d34b-da42-ebb3a34cbb99.gif)

切れている感じはなくなりましたが頭の部分が超丸いのでなんとかします。
これも本当はシムで（略）す。
先端部分を取得するためにpressureとかカスタムフィールドでなんとかしようとしましたがうまくいかなかったので地道に手でトラックして歪めてます。
![4d.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316376/be0db7e7-2eb5-cd81-393d-0a4967feec80.gif)

まあごまかせてはいるんですがクオリティ的に微妙極まりないし、まず確実にリテイクが出るやつなんですが
当記事的には、こういう方法もありますよー、というのを言いたかっただけなのでこれでよしとします。

補足。
--
wrangleでボリュームをいじれることを知りたての人が陥りそうな罠が一つ。
たとえば、レンダリング時の煙を濃くするために単純にデンシティーを10倍にしたいとします。どうやればできますか？

答え：　　f@density *= 10;　　とか打つ！

とか考えた人、はいダウト。
これでも駄目ではないんですが、そういうときはシェーダーを使ってください。これなら元データをいじることもなく一瞬です。
当方のサンプルデータでデンシティーをwrangleで単純に上げている箇所がありますがあれはあげた後に色々やっているのでその表示に必要だからです。

あと　volume wrangle　を　h18　で実装された　sop pyro solver　で使いたい人。
ノードをダブルクリックするとnullとインプットが存在するだけのネットワークに入れますので
そこにある null に gas wrangle を刺してください。上から何かを繋げる必要もありません。
文法が正しいならそれで動きます。

それとおまけ要素としてフェイクでコリジョンをつくる方法を提示したデータを用意しました。
例えばある領域のベロシティをゼロにしてデンシティを消すとその中の領域がコリジョンと似た機能を持ちます。
その例がサンプルシーンのsim内、右から二番目のotherの左側、fake collision and pop advectにあります。
これも興味があればどーぞ。

ところでなぜこの部分の解説が薄いのか？そんな時間はないからです。
この記事は１５日のアドベントカレンダーのものです今は１４日の23時半です。
そんな状況で解説とかムリムリ。

そんな感じで。