【逆引きメモ】Pixyz のスクリプトでUnityに取り込む3Dデータを自動処理する
はじめに
Pixyz Studio、Pixyz Scenario ProcessorではPythonスクリプトを使って一連の処理をバッチ化することができます。
でも、PixyzのAPIリファレンスの情報だけだと理解が苦しかったので、後から見直せるように理解した内容をメモとして残します(随時更新します)。
前提とは言いませんが、Pythonでバッチ処理を記述するのでPhytonの知識があった方が良いです。
きっと、Pythonがわかる人にとっては理解は容易なのだろうと想像します。
私はPython初心者なのでAPIを読んでも良くつまづきます。
環境
- Pixyz Studio 2022.1 Update 1 r4 (2023年3月時点で最新リリース)
目的別のScriptの書き方
1. APIリファレンスの読み方
AIPリファレンスを開くとまず左ペインにカテゴリが表示されます。
CoreGUI、Core、Geomといった名前領域を選択すると、所属する公開APIが表示されます。
Pixyz StudioのUIメニューと関連する名前もあるので、どの名前領域でどのAPIがあるかをなんとなく推測できますが、正直規則がよくわかってないです。
私がよく使うのはSceneとalgoです。
2. オカレンスの種類
Pixyzでは3Dデータ表現のことをオカレンス(Occurrence)と呼びます。
3D CADだとパーツ、アセンブリのことを指し、Unityに取り込んでからはGameObjectと呼ばれる存在です。
パーツ、アセンブリと表現したことから気づくかもしれませんが、オカレンスにも種類が存在します。
ドキュメントを参考にすると以下の通りです。
- Part occurrence :ジオメトリ情報(BrepやMesh)を持つ存在。パーツです。
- Assembly occurrence :Part occurrenceを束ねる存在。アセンブリ/フォルダです。
- Empty occurrence :何かしらの目的で作成されていますが、子階層にPart occurrenceを持たない、表現には影響がない存在。
- Light occurrence :照明情報を持つ存在。
3. Typeの理解
APIのfunctionを見るとParametersやReturnsの情報があり、Typeの記述があります。
例えばgetChildren()の場合にはOccurrenceを引数に取り、OccurrenceListを返却します。
実際にこのOccurrenceやOccurrenceListにどういう値を入れるのか、ですがScene typesに書いてある説明を読んでも具体的に理解するのが私には難しかったです。。。
これまでの経験から、Occurrenceの持つOccurrence PropertiesにあるIdで良いのかな、と理解してます。
次にOccurrenceListは何かというと、これはそのままPythonのリストで前述のOccurrenceの持つIdをリスト形式でまとめたものです。
例えば[1668,20,31]の様な形。
このOccurrenceとOccurrenceListが理解できるとPixyzのAPIが理解しやすくなります。
4. 3D CADのデータをUnityで使うために軽量化する(マージ)
3D CADは設計データなので製造をするために必要なレベルで情報が定義されています。
つまり非常に細かい情報の集合で、ボルト、ワッシャー、バネといったレベルまで独立したパーツになっています。
目的によりますが、CADのデータをそのまま使うことはなく必要ないレベルはマージした方がデータは扱いやすくなります。
APIにscene.mergeParts()があるのでそれを使うのですが、何が対象になるのかをOccurrenceListとして渡してあげる必要があります。
その絞り込みに使うのがscene.getFilteredOccurrences()です。
getFilteredOccurrencesは第一引数にFilterExpression、省略可能な第二引数にOccurrenceを指定します。
ここで第二引数を省略したら全量が対象になりますので、全Occurrenceに対して条件に該当するOccurrenceだけを絞り込むのに便利なfunctionです。
①Part Occurrenceで、かつまだMeshが貼られていないOccurrenceの一覧を取得
filter = "(Component(\"Part\") AND (Component(\"Part\").Mesh().TriangleCount().ToNumeric() < \"1\".ToNumeric()))"
filteredOccurrences = scene.getFilteredOccurrences(filter)
名前にキーワード(以下ではCaliper)を含まないOccurrenceの子階層のOccurrenceの一覧を取得
filter = 'Component(\"Part\") AND Parent().Property("Name").Matches("^(?!.*Caliper).*")'
thisOcc = scene.getFilteredOccurrences(filter)
名前にキーワード(以下ではBrake)を含むOccurrenceの子階層のOccurrenceの一覧を取得
filter = 'Component(\"Part\") AND Parent().Property("Name").Matches(".*Brake.*")'
thisOcc = scene.getFilteredOccurrences(filter)
名前にキーワード(以下ではCaliper)を含むOccurrenceの子階層のデータをMergedPartという名称のOccurrenceにマージし、不要になったカラのAssembly Occurrenceを削除
filteredOccurrences = scene.getFilteredOccurrences('Component(\"Part\") AND Parent().Property("Name").Matches(".*Caliper.*")')
core.setProperty(scene.mergeParts(filteredOccurrences)[0],"Name","MergedPart")
scene.deleteEmptyOccurrences()
Caliperを対象にMergedPartsを作成した際の様子。
Discussion