✍️

【Houdini】HeightFieldのVolumeSampleの値の取得について

に公開
2026/04/22

調べたこと

WrangleVolumeにおいて、3次元ボクセルデータの座標から指定のボリューム値を補完してとれるVolumeSample VEXですが、
HeightFieldの場合、ボクセルの座標から取れなかったので、取得の方法についてまとめました。
https://www.sidefx.com/ja/docs/houdini/vex/functions/volumesample.html

Convert HeightFieldノードでポリゴンに変換すると、マスク値が自動的にFloat値などで格納されるので、単純にこちらを使って取得してもいいのですが、HeightFieldの解像度が高すぎると、変換処理速度などがネックかなあと思ったので…

サンプルファイル: HF_volumesample.hiplc
https://github.com/yuzutarou-maru/Houdini_Sample/tree/main/houdini/HeightField

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