またまたノードではなく vex でやってみようメモシリーズです。
フェイスの選択範囲から外周のポイントを抽出してます。
下準備
このように用意したグリッドから group1
を作成します。説明でわかりやすいように 選択個所は color SOP で色を付けてあります。
実処理
まず Primitive wrangle SOP を作成し、プリミティブ(フェイス)のグループをポイントのグループに変換します。赤い文字でポイント番号が表示されているのが新たに作られた around
グループです。まだ、外周だけの状態になってはいません。
if(inprimgroup(0, "group1", @primnum)){
int points[] = primpoints(0, @primnum);
foreach(int pt;points) {
setpointgroup(0, "around", pt, 1);
}
}
プリミティブがグループに含まれているかの判定に inprimgroup
関数を使っていますが、ノードの Group
パラメータ欄に入力した方が簡単です。ここではあえて vex の処理としています。グループの指定も @group_around
のようなアトリビュート方式はとらず、setpointgroup
関数をあえて使っています。これは、それぞれが外部パラメータとして入ってくることをみこしたコード例とするためです。(ハードコードを避けやすくしている。)
さらに Point Wrangle SOP を繋ぎ、外周だけを抽出しました。
if(inpointgroup(0, "around", @ptnum)) {
int prims[] = pointprims(0, @ptnum);
int same_group_cnt = 0;
int numprim = len(prims);
foreach(int prim;prims) {
if(inprimgroup(0,"group1", prim)) {
same_group_cnt++;
}
}
if(same_group_cnt > 2 && same_group_cnt == numprim) {
setpointgroup(0, "around", @ptnum, 0);
}
}
ロジックとしては、まずグループ化された各ポイントに関連している複数フェイス(この例の場合1ポイントに最大4つ)を pointprims
関数で抜き出し 、そのうち元の group1 に属している数をカウント ( same_group_cnt
) します。全てのフェイスが group1 に属している場合は選択範囲の内側の点であると判断して around
グループ方取り除きます。ただし関連フェイス数が1の場合は全体の角のポイント、2の場合は全体の外周のポイントなのでそのまま残しています。
上記ロジックで複雑な選択状態や、三角ポリゴンを交えて試しましたが処理はうまくいっているようです。(5角形以上のいわゆるnゴンは利用する予定がないため確認していません。)
まとめ
なるべく1つの wrangle ノードで対応したかったのですが、2つに分けた方が楽だったのでそうしました。detail あたりで処理を回せばできなくはない気もしますが、SIMDで並列処理させたいのと Compile SOP で囲むこともできたのでこれでいいかなと思います。あと同じことができる SOPノードを探したのですが見つかりませんでした。ご存じの方おれば教えてください。グループノード系の設定次第で軽くできちゃいそうな予感もします。