【Houdini】HeightFieldのVolumeSampleの値の取得について
調べたこと
WrangleVolumeにおいて、3次元ボクセルデータの座標から指定のボリューム値を補完してとれるVolumeSample VEXですが、
HeightFieldの場合、ボクセルの座標から取れなかったので、取得の方法についてまとめました。
Convert HeightFieldノードでポリゴンに変換すると、マスク値が自動的にFloat値などで格納されるので、単純にこちらを使って取得してもいいのですが、HeightFieldの解像度が高すぎると、変換処理速度などがネックかなあと思ったので…
サンプルファイル: HF_volumesample.hiplc
Houdiniバージョン
Houdini Indie 20.5.332で確認
取得方法について
取得するもの
下の画像の赤いマスク部分(崖マスク)のボリューム値をとることにします。

値が取れるかどうかの確認として、以下のようにHeightFieldを包むようにBoundsを作成し、pointfromvolumeでポイントをドバーと均一にまいておきます。
このポイント位置はそれぞれのボクセルの位置にあります。

指定の崖マスクボリューム値が 0.5 以上のものを残すことにしましょう。
調べた結果、2つの方法で値がとれるみたいです。
以下の画像のポイントが白くなっていれば1に近い値が取れている状態です。
取れない場合は0の値(黒色)になります。
失敗例:普通にそのままのボクセル位置でとってみる
以下のように @P(ボクセルの位置) をそのまま使ってもとれません。
f@Cd = volumesample(1, "cliff", v@P);

取得方法1
入力の位置の Y座標を0 にする
vector pos = set(@P.x, 0, @P.z);
f@Cd = volumesample(1, "cliff", pos);
if(f@Cd < chf("threshold")){removepoint(0, @ptnum);}
崖マスクの部分のボリュームが取れてますね!

取得方法2
方法2では下の二つの順序でとることができます。
1.primitive Propertiesノードを設定する
primitive Propertiesノード
のVolumesタブ > Volumes タブにいき、
- Adjust Borderにチェック
- Border Type を
Streakに変更
2.VEXノードでボクセル位置で取得
f@Cd = volumesample(1, "cliff", v@P);
if(f@Cd < chf("threshold")){removepoint(0, @ptnum);}
こちらはボクセル位置で取得できましたね!

値が取れる理由
値がとれたものと取れなかったものの違いはVolumeのborderTypeが関係しています。
borderTypeはPrimの隠しアトリビュートのvolume border typeを有効にすると確認できます。
取れなかった方のBorderTypeはconstantに設定されており、これはボクセル外の場合指定の値を取得するものです。通常はその値が0なのでボリューム値はとれません。
値が取れたほうはstreakとなっており、これはボクセル外でも最寄りのボリューム値をとることができます。

ただし注意点として、HeightFieldはいわゆる2Dボリュームといわれ、厳密な3次元ボクセルデータではありません。
あくまでテクスチャのような2次元配列構造で、@heightボリュームの値(Float値)で立体的に見せているような形となります。
そのため下の画像で少しわかりにくいですが、
HeightFieldで取得した値は高さ対してすべて均一な値をとるので、HeightFieldの表面を反映した値をとりたい場合は工夫が必要です。

レイヤー近くのポイントを取得する方法は、HeightFieldのバウンドY軸の長さを上限として、
それぞれのポイントの最寄りのHeightFieldの高さとの差分をとり正規化するとある程度取得できました!
(ただし、HeightFieldがペライチ形状だとうまくいかないと思うので注意が必要です!)
//HeightFieldのboundsの縦方向をMAXとし、それぞれのポイントとの距離を測る
float bounds[] = detailintrinsic(1,"bounds");
float sizeY = bounds[3]-bounds[2];
float height = volumesample(1,"height",v@P);
//v@P.y= height;
float dist = abs(v@P.y-height)/sizeY; //距離
float ratio = fit01(dist,0,1); //正規化
vector pos = set(@P.x, 0, @P.z);
f@Cd = volumesample(1, "cliff", pos) * (1.0-ratio);
if(f@Cd < chf("threshold")){removepoint(0, @ptnum);}

Discussion