Houdiniで長方形のプリミティブを判別するノードを作成した
primitiveが長方形かどうか判別するノードを作った。長方形やそれ以外の部分にそれぞれグループを与えたり、長方形の部分やそれ以外の部分をそれぞれ削除したり、長方形以外が含まれていたらエラーを起こしたりできる。#Houdini pic.twitter.com/xCnKGRn87V
— 折登 いつき (@MatchaChoco010) 2018年12月30日
ノードの全体図は次のようになっています。
上から順に見ていきます。
左側にあるnullはコントローラ用のノードです。
右側にはテスト用のジオメトリをまとめたサブネットがつながっています。 テスト用でしかないので今回は解説しません。 switchでテスト用ジオメトリと正規の入力を切り替えられるようにしてあります。 テスト時以外は通常の入力がそのまま渡されます。
コントローラ用のnullノードは次のようになっています。
2019/09/19 追記
2019/09/19 追記ここまで
switchの下は2つに分岐しています。 Groupで与えられたもの以外を削除するものと、 Groupで与えられたものを削除するものに分岐しています。 Group以外を削除したものに対して処理を行うことで、 Groupに対する処理としています。
Groupに対する処理はPrimitive Wrangleノードに記述されています。 このノードが一番のメインのノードになります。
次のようなコードを記述しています。 (2019年1月11日 プログラム修正)
int vcount = primvertexcount(geoself(), @primnum);
int closed = primintrinsic(geoself(), "closed", @primnum);
string typename = primintrinsic(geoself(), "typename", @primnum);
if (vcount != 4 || !closed || typename != "Poly") {
setprimgroup(0, "isRectangle_nonRectangle", @primnum, 1);
return;
}
int pt0 = primpoint(geoself(), @primnum, 0);
int pt1 = primpoint(geoself(), @primnum, 1);
int pt2 = primpoint(geoself(), @primnum, 2);
int pt3 = primpoint(geoself(), @primnum, 3);
vector p0 = point(geoself(), "P", pt0);
vector p1 = point(geoself(), "P", pt1);
vector p2 = point(geoself(), "P", pt2);
vector p3 = point(geoself(), "P", pt3);
vector v01 = p1 - p0;
vector v12 = p2 - p1;
vector v23 = p3 - p2;
vector v30 = p0 - p3;
if (
abs(dot(v01, v12)) < 1e-5 &&
abs(dot(v12, v23)) < 1e-5 &&
abs(dot(v23, v30)) < 1e-5 &&
abs(dot(v30, v01)) < 1e-5
) {
setprimgroup(0, "isRectangle_rectangle", @primnum, 1);
} else {
setprimgroup(0, "isRectangle_nonRectangle", @primnum, 1);
}
頂点数が4ではない、ポリゴンではない、閉じていないものを最初にisRectangle_nonRectangle
というグループに入れてreturn
しています。
これでカーブなどを除外しています。
次にポイントの座標を取得して辺のベクトルを計算しています。
隣り合った辺のベクトルの内積が0のとき直角になっていることがわかります。 浮動小数点数の誤差のため完璧に0にはならないようなので 適当に小さい数字を指定しました。
4つの角がすべて直角のときisRectangle_rectangle
グループに、
それ以外のときはisRectangle_nonRectangle
グループに格納しています。
isRectangle
をプリフィクスとしてつけることで既存のグループ名とかぶらないようにしています。
その後MergeノードにつないでFuseノードもつないでいます。
その下にErrorノードをつなぎます。
エラーメッセージはコントローラで指定したものを表示するようにしています。
エラーを表示する条件式には次のように記述します。
ch("../null1/raiseAnErrorWhenNonRectangleIsIncluded") && nprimsgroup("../fuse1", "isRectangle_nonRectangle") != 0
コントローラでエラーを発生させるチェックが付いていて、
さらにfuseノードにisRectangle_nonRectangle
グループの数が0でないときにエラーを出します。
次にBlastとswitchを次のようにつなぎます。
非長方形を削除するチェックが付いているときにはswitchで削除したほうが出力されます。
同様にして長方形を削除するチェックが付いているときには削除しています。
その後はグループを削除するか、グループを与えた名前にリネームするかで分岐しています。
左側はGroupDeleteノードでisRectangle_rectangleグループを削除しています。
右側はGroupRenameノードでisRectangle_rectangleグループを 与えられた名前でリネームしています。
コントローラのチェックボックスでこれらを切り替えるようにしています。
長方形以外のグループ名についても同様の処理を行っています。
hda化して使い回しが効くようにまとめて完成です。
入力のprimitiveが長方形であることを前提とした処理を書きたくなったので、 そのチェックのためにこのノードを作成しました。