すあまの備忘録

誰得内容の自分のための非営利目的備忘録ブログ(筆者がわかっても内緒にしてください)

Water Explosion

この前X(Twitter)に投稿しもののざっくり説明

今までと違い期限を決めずに合間でちまちまやっていた。このくらいのペースで何か作っていくのは良さそう。

GridのRemeshとWhite WaterのVolume化はH20でかなり楽になった印象。

youtu.be

まとめ

一定の条件でしか使えない削減処理をちょこちょこ入れているので使いどころが限られる。

あまり意味がない部分もあったがH20のノードをなるべく使っているつもり。

Scene File

splash_v007_gd.hiplc - Google ドライブ

アセット

Poly HavenのKloofendal 48d Partly Cloudy

Nukeで追加している遠景の山はLocation TextureのFree Panoramic Clouds

Ocean Far / Ocean Spectrum

ベースメッシュ

海抜が0のときに見える水平線の距離はだいたい4kmくらいらしいので5kmくらいあるグリッドを作成

H20から追加されたRemesh to Cameraでカメラからの距離に応じてメッシュを分割します。

ちなみにMeasureをKarma DicingにしてDicing QualityをRender Geometry Settings LOPと一致させると実際にディスプレイスメント時に分割されるだけのメッシュになります。

Ocean Spectrum作成

限られたエリアで見た目や動きを確認してOcean Spectrumを作成

Particle Fluid MaskのFilter機能で低、高周波を分離する。

Far Mesh

ベースメッシュから、シムする予定のエリアを削除します。

今回は1レイヤーでまとめてレンダーしてますが、実際は削除エリアを少し狭めてオーバーラップさせてコンプで境界をなじませるほうがいいです。

このようにレンダー時に境界線が目立ってしまう場合があります。(動画にもそのまま残しているので見てみてください)

押し出して厚みをつけたのち、Ocean Evaluateで低周波、大きな波の動きだけ適応します。

FLIP

Emitter

こういう感じのものを作る。手で動かしてもいいし、FLIPが望みのエミット具合になればOK

今回はemitframedurというアトリビュートでエミットとエミット継続時間を制御しつつ、下記のようなVEXでCopy to Ponitsしつつ半自動で動くように処理

float pscale = chramp("scale", fit(@Frame, f@emitframe, f@emitframe + f@dur, 0, 0.7));
float pscaleB = 0.04;

v@scale = set(pscaleB, pscale, pscaleB);
//
f@bend = chramp("bend", fit(@Frame, f@emitframe, f@emitframe + f@dur, 0, 1));
f@bend = fit01(f@bend, -2, -2);

vector4 q = quaternion(radians(@bend)*-1, @N);
v@up =  qrotate(q,@up);

そのままTrailでVelocityを計算するとものすごく高いvができるので、以下VEXで丸め込み。

float speed = length(v@v);
vector dir = normalize(v@v);

float threshold = chf("threshold");

if(speed >= threshold) {
    speed = log(speed-threshold +1) +threshold;
}
v@v = speed * dir;

thresholdを40にして40以上のvの上がり具合を緩やかにする。図にすると以下の様な感じ。

で、その結果をemitframedurの範囲内以外のエミッターを削除

if(@Frame < f@emitframe || @Frame >= f@emitframe + (f@dur)) {
    removepoint(0,@ptnum);
}

FLIP Boundary

FLIP Sim

White Waterのエミッターになればいいのであまり細かく調整はしない。

FLIP Solver SOPを基本にしてPOP Force等で少し散らす。

キャッシュを圧縮して保存する。この部分はHDA作って処理してたので参考データからは削除。

FLIP Meshing

FLIP部分はなるべく感じないように削除したいので削除処理をする。Pointも処理しているが問題なければSurfaceだけでもいいと思う。

FLIP Pointに対してFLIP SurfaceからVolumeの値を取得する。

f@density = volumesample(1,'surface',@P);

Remapのち、密度の高い部分やvorticityの高い部分でpscaleを調整する。

float mult = 1;
float dens = fit01(f@density, 0, 1);
float vrt = fit(f@vorticity, 5, 10, 0, 0.5);
f@pscale *= dens * vrt;

このPointと、SurfaceP.y >= 1を0にしたVolumeを用意。

Point、SurfaceにさらにOcean Farから削った部分が四角なのでそこを補うVolumeを用意してすべてを結合する。

シムの範囲

補う範囲

段差が出る場合があるのでP.y等で段差を軽減し、Ocean EvaluateでOcean SpectrumのLowを適応する。

White Water

White Water Preparation

White Waterのエミッターとして使う際に邪魔になりそうな部分のPointに対して以下のようなVEXでpscaleを調整する。

float mult = 1;
float range = fit(@P.y, 1, 8, 0.05, 0.015);
float vrt = fit(f@vorticity, 1, 10, 0, 1);
float spd = fit(f@speed, 0, 10, 0, 1);

if(f@vorticity >= 0.02 && @P.y >= 1) {
    mult *= vrt;
}

f@pscale = range * mult;

VDB from Points等でVDBにした後ポリゴンに変換。

Boundary作成時のカーブからの距離を取得する。

vorticityspeed( length(v@v) )が低い部分のP.yを0にする。

Ocean EvaluateでLowのOcean Spectrumを適応する。

White Water Emitter

White Water Souce SOPとWhite Water Solver SOPを使っているけどぶっちゃけPOPでも可

White Waterはほぼそのままエミットさせているだけなので説明はざっくり。

White Water Souce SOPのCurvature, Acceleration, Vorticityを調整してそれっぽいエミッターを作る。

そこからemit Volumeが高すぎたりしたらVolume Wrangle等で調整をする。

何故かWhite Water Solver SOPのBuoyancyがDOP内のWhite Water Solver DOPのBuoyancyにつながっていなく、勝手に浮いてしまうのでAllow Editing Contentsをして内部に値をつなぐこと。

White Water Post-Process

White Water Post-Process SOPが追加されたのでこれを使う。

諸々の設定はヘルプを見たほうが早いが、影があまり強く落ちない飛沫を作る場合は

コツとして設定するDensityの値を高くせずにエミットさせるポイントの数を増やすのがいいと思う。

densityを高い値にしてしまうとPointが密な部分がかなり高いDensityになってしまい、強い影が落ちやすくなる。全体の濃度が足りない部分はエミットしているポイントが足りないか、レンダーで一律にVolumeに対してやるといい。

今回はこれ以外にもWhite Waterと更にそこからエミットした薄く拡散するポイント、FLIPのPointの流用をまとめてWhite Waterとして扱ってポイントのシムコストが下げつつポイント数を確保している。

White Water Volume化

H20で追加されたVDB Rasterize Frustumを使ってVolume化。

これはカメラ範囲および距離で解像度が調整されたVolumeを作成することができるので、遠景の場合に従来より軽いVolumeを作成することができる。

カメラブラーやvをもとにしたVolumeの疑似ブラー処理もできるのでかなり便利。

ただし遠景から近景に近づいてくる場合などはVolumeの解像度の切り替わり部分が目立つ場合がある。

第一入力にPointを、第二入力にVDBノードをつなぐ。

VDBノード側で作成するVolume名、カメラ周りの設定と最後で解像度を指定する。

Uniform Samplingが設定する際の基準軸になる。今回は画面の横がX軸なのでそれを基準にし、Z Scaleで奥行き方向の解像度を決める。

作成されたVolumeはXYZそれぞれの解像度が異なるものが作成される。

これで作成される解像度はかなり攻めた値で設定できるのもメリット。

設定例

Rendering

原則全てをUSD化してLOPに読み込む。

Houdini Procedural: Ocean

H20からのHoudini Procedural: Oceanを使う。

Ocean SpectrumにはHighのほうのOcean Spectrumをつなぐ。

このノードは内部でSOP Importを使用して直接ジオメトリを読み込んでいるので、外部ファイルのUSDを読み込みたい場合はこの部分をReferenceノードなどに差し替える。その他に、今回はOcean InteriorもMaterialもそのままは使ってない。

差し替えた場合は以下の場所を注意。画像の指定部分は書き出し方によって異なるので注意。

dicing_and_bumpmap_settingsのPrimitivesにレンダリングするメッシュの一つ上の階層を指定

define_and_setup_ocean_procedural_surfaceのProcedural Primにレンダリングするメッシュそのものを指定

Interiorの代用

全範囲をカバーできるくらい大きなGridをY軸方向に下げて用意

これに自己発光のみのマテリアルをアサインする。今回の手法ではこれが=海の色になる。このGridの色を変えれば簡単に海の色が変わるので海の深さが認識できない画の場合は手軽で便利で内部のVolumeもいらないので計算が若干速い。

ノイズで部分的に色を変えるなども用意

Ocean Near / Far

Houdini Procedural: Ocean経由で読み込んだ2つのメッシュに対してほぼ屈折のみのマテリアルをアサインする。

White Waterとのなじませ箇所はvorticityなどのアトリビュートを使用して白いマテリアルとMixする。

White Water

Pyro Shaderを使用してざっくり暗部が青っぽい煙をつくる。

Density Scaleで最後の調整をするが、この際に濃い影の部分が生まれた場合はPointのDesnityアトリビュートの値が高い可能性があるのでVolume化前の処理からやり治すのが早い。