前回の記事 で、ジオメトリへノイズを適用した際などに発生する裏返り部分を除去するアプローチを考察していました。
本記事に記載してあるものは、その際に無用であると判断した記述です。失敗の中にもヒントはあるという信条のもと、ここに記録として残します。
シーンデータは前回の記事同様、 こちら からダウンロードできます。
シーン中の、approach_mesh OBJ 内の右端に置いてある omitted_approach ジオメトリノードが、本記事に該当するものです。
Point Cloud Surface SOP は、裏返っていると推定される部分をジオメトリ生成対象から除外する挙動をします。そのことに気付いていなかったことが、本記事の記載につながりました。
肝となるSOP
Point Cloud Surface SOP を使用します。この SOP は主にフォトグラメトリで使用されるもので、法線を持つ点群をもとにポリゴンを作成します。
アプローチ
このアプローチではジオメトリの表面に点群が必要になります。ですがジオメトリへ直接 Scatter SOP を使用した場合、除去するべき裏返った場所にも点ができてしまいます。そこで以下の方法により点群を用意します。
- ジオメトリから離れた位置に点群を生成する
- 点群をジオメトリへ向かって投射する
- 衝突部分の primitive 法線と投射方向をもとに、その部分の表裏を判定する
- ジオメトリが表の場合、衝突部分へ点を移動し、その部分の primitive 法線を点へコピーする
(ジオメトリの裏返っていない部分へのみ点群を付着させる) - 点群の投射を四方八方から行うことで、裏面以外を点群で包む
投射開始位置と投射方向
ジオメトリの外から点群を投射するために、ジオメトリ内に点が生成されないようにする必要があります。
球の生成
Bound SOP はジオメトリを内包する箱を作成しますが、箱ではなく球で作成することもできます。デフォルトでは大雑把なサイズの球になりますが、Accurate Bounds パラメータをオンにすることで、より効率的な球が生成されます。
この球に散布した点群はジオメトリの内部には位置しません。それを球の中心方向へ投射することでジオメトリを点群で包めます。
ですが、そうすると球の中心と外側で点の投射密度が大きく異なり、Point Cloud Surface 適用時にかなりシルエットが崩れてしまいます。そのため、次のようにもうひと工夫します。
平面の複製と点群の作成
球面上に平面を置き、その平面へ点群を散布することで、投射時に点群密度が偏るのを多少防ぐことができます。
下図はそのイメージで、左側は球の中心に近づくほど点群密度が高まるのに対し、右側は均等な投射ができていることが判ります。
そのため、点群生成を次のように行います。
- Bound で作成した球へ Scatter SOP で点群を作成する
- その点群へ Copy to Stamp SOP により板のジオメトリを複製する
- 複製された板へ改めて点群を生成する
実際には複製した板へ点群を散布するより、板へ散布した点群を複製したほうが高速に処理できるため、サンプルではそのようにしています。
衝突部分の裏表を判定
投射時に裏面を避ける仕組みを含めるため、VEX の intersect 関数と primuv 関数を使用します。
- intersect
- 任意の場所から指定した方向へジオメトリを探し、衝突部分の情報を取得します。引数 dir の長さはジオメトリを探す距離も意味することに注意する必要があります。
- primuv
- intersect などから入手できる情報を使用して、衝突部分の primitive から情報を取得します。
primuv で取得したジオメトリ法線と、投射した方向との内積がプラスであれば、その衝突面は裏面だとみなせます。裏面に衝突したと判定された点と、そもそもジオメトリへ衝突しなかった点は、不要なので削除します。
このアプローチで四方八方から点群を付着させ、法線を取得したうえで Point Cloud Surface を適用するとジオメトリが再構築されます。
結果
このアプローチを採った場合の結果は図の通りです。