この前X(Twitter)に投稿しもののざっくり説明
今までと違い期限を決めずに合間でちまちまやっていた。このくらいのペースで何か作っていくのは良さそう。
GridのRemeshとWhite WaterのVolume化はH20でかなり楽になった印象。
まとめ
一定の条件でしか使えない削減処理をちょこちょこ入れているので使いどころが限られる。
あまり意味がない部分もあったが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
今回はemitframe
とdur
というアトリビュートでエミットとエミット継続時間を制御しつつ、下記のような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の上がり具合を緩やかにする。図にすると以下の様な感じ。
で、その結果をemitframe
とdur
の範囲内以外のエミッターを削除
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と、SurfaceのP.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作成時のカーブからの距離を取得する。
vorticity
やspeed( 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化前の処理からやり治すのが早い。