4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Houdini ApprenticeAdvent Calendar 2024

Day 12

Houdiniでパーツ干渉チェッカーを作った話

Last updated at Posted at 2024-12-11

はじめに

この記事はHoudini Apprentice Advent Calendar 2024 12日目の記事です。

はじめまして!
フィギュア原型師をしております空都凪はとです!

メインツールはZBrushなのでHoudiniはサブウェポンな感じですが、Houdini触るのが大好きです!

今回はタイトルの通り、Houdiniでパーツの干渉をチェックする仕組みを作ったお話を書こうと思います。

まだまだ実務でバリバリ使えているわけではない若輩者故、お見苦しい部分もあるかと思いますが、知らないソフトに興味があるデジタル造形分野の皆様、違う分野での使われ方に興味があるHoudinistの皆様、温かい目で見ていただければ幸いです。

発端と目的

フィギュアの原型データ作成の中で、分割という大変な工程を終えた後、いざ出力パーツを出力したらダボや分割面の引き忘れでパーツがはまらない...というのは誰もが考えたくないものだと思います。
ましてや出力の仕事をしている時であればなおさらです。

前職でそんな失敗を経験したさい、自動でチェックできる仕組みがあればいいのになと思ったのが発端です。

わたしはアプリケーションの開発ができるわけではなかったため、「自動化」が可能なHoudiniでそのチェックができる仕組みを作ることを目的に開発をしてみました。

全体の流れ

まずは今回作ったものの流れを軽く説明します。
2024y12m10d_145702888.png

1.判定したい分割済みオブジェクトをインポート

2.ゼロクリアランス対策で少しだけ縮める

3.交差判定を行う

4.3で行った判定の際に付与したアトリビュートをもとに色を付ける

こうして段階ごとにまとめて書くと、やっていること自体はかなり単純だと認識できるはずなのに、いざ仕組みを作るとなると、なかなか大変な部分もあったので、そのあたりも紹介できればと思います。

今回は実用性を考えて2通りの表示方式を作成しました。
ある1つのメッシュに着目した場合、交差そのものがあるかどうか、またそれがどれと交差しているのかを視覚的にわかるようにしています。
2024y12m10d_153307195.png

先の例では単純なスフィア同士で判定を行っていましたが、実際の分割済みのフィギュアデータでも検証を行っています。(こちらは2つ目の表示方式です)
2024y12m10d_152823268.png

入力

分割してSTLとして書き出したデータ群を読み込み、それぞれにclassアトリビュートを付与したものをインプットとして使用します。
複数のファイルの読み込みでFilemergeを使用する場合、File Name Attributeにチェックを入れて、ファイルごとにnameアトリビュートを付与しておくと扱いやすいです。

2024y12m10d_160316982.png
恐らくHoudiniの仕様だと思いますが、STL形式のデータを読み込むとポリゴンが反転してしまっているのでreverseを繋ぎ、enumerateを使ってnameアトリビュートからclassアトリビュートを作成します。

少しだけ縮める

交差判定を始める前に、それぞれのメッシュをほんの少しだけ縮めます。
今回作成したシーンでは0.1mmずつ縮めています。

これには後の交差判定の工程で使用するIntersection Analysisの性質が関わってきます。
Intersection Analysisは、自己交差は無視したうえで2つのインプット同士の交差箇所をポイントとして出力してくれますが、この「交差箇所」には「交差はしていないが重なっている部分」も含まれてしまいます。

そのため、分割のブーリアンをゼロクリアランスで行っている場合は全体を少し縮めてやらないと、全体が接触していることになってしまいます。

2024y12m10d_162328771.png
左が縮小あり(出力ポイントなし)で右が縮小なし(出力ポイントあり)

最初の例のように単純なメッシュを扱うのであればpeakを使うだけで済むのですが、ほぼすべてが複雑な形状をしているので、今回はコントローラーとして使用しているnullに「use_complex_offset」というトグルスイッチを設定したうえで、ボリュームを使用した収縮を実装しています。
2024y12m10d_163007374.png

操作自体はあくまで少量の収縮なので、
1.VDB from PolygonsでパーツのメッシュをVDB化

2.VDB Reshape SDFで均一に収縮

3.Convert VDBでVDBをポリゴンに戻す

4.3に対して元のメッシュをAttribute Wrangleで被せる
という流れで行っています。

VDBで収縮させたメッシュに元のメッシュを被せる
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を用いて行い、その結果から必要な情報を引き出すという割と力業な手法を取っています。
2024y12m10d_164946931.png

画像内のattributewrangle112ではIntersection Analysisで生成されたポイントが、どのメッシュとの交差によって生じたのかを探索しています。(交差しているメッシュのclassアトリビュートをxyzdistを使って検索する)
2024y12m10d_165006966.png

生成されたポイントごとに、交差しているメッシュのclassアトリビュートを検索する
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アトリビュートを作成しています。
2024y12m10d_165018039.png

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");

色を付ける

ここまでで欲しい情報は出揃ったので、後は視覚的にわかりやすい表示にしていきます。
2024y12m10d_170849394.png

まずはattributewrangle116で、事前にRest Positionで設定しておいたrestアトリビュートを使って縮ませていた形状をもとに戻します。

縮める前の形状に戻す
@P=@rest;
交差が有るか無いかだけで色分け(1つ目の手法)

attributewrangle116から左側に流れているものです。
こちらはごく単純で、Groupを使って交差の有無を示すdetectionアトリビュートが1のものをグループを作り、それだけをColorで別の色で塗るというだけです。

2024y12m10d_181712417.png
ここでは
交差あり → 赤
交差なし → 青
という色分けになっています。

ある1つのメッシュに着目して周りがどうかも含めて色分け(2つ目の手法)

こちらは実質attributewrangle1171つだけです。
Extract Centroidはポイントだけにした方がジオメトリスプレッドシート上で数値として確認しやすくなるためです。(こちらはスフィア群の例)
2024y12m10d_171927519.png

メインとなる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;
        }
}

こちらのコードでは、
着目しているものが交差判定を持っていない → 緑
着目しているものが交差判定を持っている  → 赤
着目しているものと交差している      → 黄
それ以外                 → 青
というような色分けになっています。

2024y12m10d_173423003.png
2024y12m10d_173500731.png

コントローラーの作成

最後にこれらを扱いやすいようにコントローラーを作りました。
特に色の指定についてはカラーサークルを使えるのでかなり楽になりました。
2024y12m10d_173807031.png

開発を振り返って

実は今回の開発自体はかなり前から構想があり、今回ようやく形にすることができました。

特に交差判定を行う部分は構想初期からアルゴリズムが二転三転して今に至っています。
最初はポイントのアトリビュートを持たせて複数のループを作ってnC2の組み合わせを作って処理しようとしていましたし、そのうえBooleanIntersectではうまくいかないことに気づいて愕然としたりしていました。

途中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

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?