はじめに
この記事はHoudini Apprentice Advent Calendar 2024 12日目の記事です。
はじめまして!
フィギュア原型師をしております空都凪はとです!
メインツールはZBrushなのでHoudiniはサブウェポンな感じですが、Houdini触るのが大好きです!
今回はタイトルの通り、Houdiniでパーツの干渉をチェックする仕組みを作ったお話を書こうと思います。
まだまだ実務でバリバリ使えているわけではない若輩者故、お見苦しい部分もあるかと思いますが、知らないソフトに興味があるデジタル造形分野の皆様、違う分野での使われ方に興味があるHoudinistの皆様、温かい目で見ていただければ幸いです。
発端と目的
フィギュアの原型データ作成の中で、分割という大変な工程を終えた後、いざ出力パーツを出力したらダボや分割面の引き忘れでパーツがはまらない...というのは誰もが考えたくないものだと思います。
ましてや出力の仕事をしている時であればなおさらです。
前職でそんな失敗を経験したさい、自動でチェックできる仕組みがあればいいのになと思ったのが発端です。
わたしはアプリケーションの開発ができるわけではなかったため、「自動化」が可能なHoudiniでそのチェックができる仕組みを作ることを目的に開発をしてみました。
全体の流れ
1.判定したい分割済みオブジェクトをインポート
↓
2.ゼロクリアランス対策で少しだけ縮める
↓
3.交差判定を行う
↓
4.3で行った判定の際に付与したアトリビュートをもとに色を付ける
こうして段階ごとにまとめて書くと、やっていること自体はかなり単純だと認識できるはずなのに、いざ仕組みを作るとなると、なかなか大変な部分もあったので、そのあたりも紹介できればと思います。
今回は実用性を考えて2通りの表示方式を作成しました。
ある1つのメッシュに着目した場合、交差そのものがあるかどうか、またそれがどれと交差しているのかを視覚的にわかるようにしています。
先の例では単純なスフィア同士で判定を行っていましたが、実際の分割済みのフィギュアデータでも検証を行っています。(こちらは2つ目の表示方式です)
入力
分割してSTLとして書き出したデータ群を読み込み、それぞれにclass
アトリビュートを付与したものをインプットとして使用します。
複数のファイルの読み込みでFilemergeを使用する場合、File Name Attributeにチェックを入れて、ファイルごとにname
アトリビュートを付与しておくと扱いやすいです。
恐らくHoudiniの仕様だと思いますが、STL形式のデータを読み込むとポリゴンが反転してしまっているのでreverseを繋ぎ、enumerateを使ってname
アトリビュートからclass
アトリビュートを作成します。
少しだけ縮める
交差判定を始める前に、それぞれのメッシュをほんの少しだけ縮めます。
今回作成したシーンでは0.1mmずつ縮めています。
これには後の交差判定の工程で使用するIntersection Analysisの性質が関わってきます。
Intersection Analysisは、自己交差は無視したうえで2つのインプット同士の交差箇所をポイントとして出力してくれますが、この「交差箇所」には「交差はしていないが重なっている部分」も含まれてしまいます。
そのため、分割のブーリアンをゼロクリアランスで行っている場合は全体を少し縮めてやらないと、全体が接触していることになってしまいます。
左が縮小あり(出力ポイントなし)で右が縮小なし(出力ポイントあり)
最初の例のように単純なメッシュを扱うのであればpeakを使うだけで済むのですが、ほぼすべてが複雑な形状をしているので、今回はコントローラーとして使用しているnullに「use_complex_offset」というトグルスイッチを設定したうえで、ボリュームを使用した収縮を実装しています。
操作自体はあくまで少量の収縮なので、
1.VDB from PolygonsでパーツのメッシュをVDB化
↓
2.VDB Reshape SDFで均一に収縮
↓
3.Convert VDBでVDBをポリゴンに戻す
↓
4.3に対して元のメッシュをAttribute Wrangleで被せる
という流れで行っています。
float maxdist = chf("maxdist");
float mix = chf("mix");
@d = xyzdist(1,@P,i@pr,v@uv);
vector trans = primuv(1,"P",@pr,@uv);
vector rest = @P;
@P = trans*mix + rest*(1.0-mix);
交差判定を行う
いよいよ肝である交差判定を行います。
これはパーツそれぞれに対して、それ以外のすべてとの交差があるかどうかをIntersection Analysis
を用いて行い、その結果から必要な情報を引き出すという割と力業な手法を取っています。
画像内のattributewrangle112
ではIntersection Analysis
で生成されたポイントが、どのメッシュとの交差によって生じたのかを探索しています。(交差しているメッシュのclass
アトリビュートをxyzdistを使って検索する)
float maxdist = chf("maxdist");
@d = xyzdist(1,@P,i@pr,v@uv,maxdist);
if( @pr==-1 ){
removepoint(0,@ptnum);
}else{
i@contact=prim(1,"class",@pr);
}
次のattributewrangle110
では、交差がの有無を判定するdetection
アトリビュートと交差しているメッシュのclass
アトリビュートをリスト化したcontact_list
アトリビュートを作成しています。
int contact_list[];
for( int i=0; i<npoints(1); i++ ){
int contact = point(1,"contact",i);
if(find(contact_list,contact)<0){
append(contact_list,contact);
}
}
int detection;
if(len(contact_list)>0){
detection = 1;
}else{
detection = 0;
}
i@detection = detection;
i[]@contact_list = sort(contact_list);
i@class = detail(2,"iteration");
色を付ける
ここまでで欲しい情報は出揃ったので、後は視覚的にわかりやすい表示にしていきます。
まずはattributewrangle116
で、事前にRest Positionで設定しておいたrest
アトリビュートを使って縮ませていた形状をもとに戻します。
@P=@rest;
交差が有るか無いかだけで色分け(1つ目の手法)
attributewrangle116
から左側に流れているものです。
こちらはごく単純で、Groupを使って交差の有無を示すdetection
アトリビュートが1のものをグループを作り、それだけをColorで別の色で塗るというだけです。
ここでは
交差あり → 赤
交差なし → 青
という色分けになっています。
ある1つのメッシュに着目して周りがどうかも含めて色分け(2つ目の手法)
こちらは実質attributewrangle117
1つだけです。
Extract Centroidはポイントだけにした方がジオメトリスプレッドシート上で数値として確認しやすくなるためです。(こちらはスフィア群の例)
メインとなるattributewrangle117
では、着目するメッシュをclass
アトリビュートを使って指定し、それが交差判定を持っているかどうか(detection
アトリビュートが1かどうか)、交差しているのであれば何と交差しているのか(contact_list
に格納されているものはなにか)、この2つをもとに着色していきます。
vector focus_color_normal = chv("focus_color_normal");
vector focus_color_error = chv("focus_color_error");
vector contact_color = chv("contact_color");
vector unconnected_color = chv("unconnected_color");
int focus_num = chi("focus_num");
int contact_list[] = point(1,"contact_list",focus_num);
if( prim(0,"detection",@primnum)==1 ){
if( @class==focus_num ){
@Cd = focus_color_error;
}else{
if( find(contact_list,@class)>-0.5 ){
@Cd = contact_color;
}else{
@Cd = unconnected_color;
}
}
}else{
if( @class==focus_num ){
@Cd = focus_color_normal;
}else{
@Cd = unconnected_color;
}
}
こちらのコードでは、
着目しているものが交差判定を持っていない → 緑
着目しているものが交差判定を持っている → 赤
着目しているものと交差している → 黄
それ以外 → 青
というような色分けになっています。
コントローラーの作成
最後にこれらを扱いやすいようにコントローラーを作りました。
特に色の指定についてはカラーサークルを使えるのでかなり楽になりました。
開発を振り返って
実は今回の開発自体はかなり前から構想があり、今回ようやく形にすることができました。
特に交差判定を行う部分は構想初期からアルゴリズムが二転三転して今に至っています。
最初はポイントのアトリビュートを持たせて複数のループを作ってnC2の組み合わせを作って処理しようとしていましたし、そのうえBooleanのIntersect
ではうまくいかないことに気づいて愕然としたりしていました。
途中ChatGPTに聞きながらPythonを書いたりもしましたが結局はVEXでの処理に落ち着きました。
こうした試行錯誤を重ねていく毎に、自分が手を伸ばせる範囲が広がっていくことを感じられてとても楽しかったです。
最後に
まずはここまで記事を読んでいただきどうもありがとうございました。
今回の実装ではvdbの処理があったり、Intersection Analysis
の処理の軽量化が出来なかったり等、計算効率という面で大きな課題が残る結果になりました。
今後は実務でも使えるようにしていきたいと思っているので、良い案を思いついたら改善していきたいです。
また、ここまで読んでくださった方の中で、改善案をお持ちの方がいらっしゃいましたら、わたしのX(旧Twitter)までご連絡を頂けると幸いです。
ご要望があればhipファイルもお渡しします。
参考ページ(最終的に使用しなかったものも含む)
xyzdist()は何ができるのか?
https://support.borndigital.co.jp/hc/ja/articles/360008833434-xyzdist-%E3%81%AF%E4%BD%95%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%AE%E3%81%8B
primuv()は何ができるのか?
https://support.borndigital.co.jp/hc/ja/articles/360008837974-primuv-%E3%81%AF%E4%BD%95%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%AE%E3%81%8B
Move point to volume "surface"
https://www.reddit.com/r/Houdini/comments/159y4yr/move_point_to_volume_surface/
Volume Gradient VOP
https://houdinifx.jp/blog/volume-gradient-vop/
H16新機能 コンパイルブロック 1
https://houdinifx.jp/blog/h16%E6%96%B0%E6%A9%9F%E8%83%BD-%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF-1/
【ゼロから始めるHoudini】 10 - 処理の効率を考えよう
https://www.youtube.com/watch?v=S8Ynsvl-xSU
find VEX function
https://www.sidefx.com/ja/docs/houdini/vex/functions/find.html
hou.Geometry class
https://www.sidefx.com/ja/docs/houdini/hom/hou/Geometry.html#setArrayAttrib
array: remove same values?
https://www.sidefx.com/forum/topic/61012/
配列
https://www.sidefx.com/ja/docs/houdini/vex/arrays.html
【Python】リスト内の要素の全ての組み合わせを出力
https://qiita.com/Mohrey/items/b0afc8edc5fed742b68a
Houdiniで利用できるスクリプトについて
https://houdinifx.jp/blog/houdini%E3%81%A7%E5%88%A9%E7%94%A8%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/
random_shash VEX function
https://www.sidefx.com/ja/docs/houdini/vex/functions/random_shash.html
I need a random color for the connected pieces...
https://forums.odforce.net/topic/47345-i-need-a-random-color-for-the-connected-pieces/
Houdini Basics - Using the Performance Monitor to Profile Nodes
https://www.youtube.com/watch?v=uJFuvTb0OSU
パフォーマンスモニタペイン
https://www.sidefx.com/ja/docs/houdini/ref/panes/perfmon.html
chatGPT:Houdini Python nC2 組み合わせ
https://chatgpt.com/share/675804f1-3bb8-8004-b3cd-623afd463e1e
chatGPT:配列に値を追加
https://chatgpt.com/share/67580556-9a3c-8004-8ee1-ea3d8055d454