Skip to content

UsdCollectionを使おう

USDの「Collection」とは、MayaのSetsと似た機能で
USDシーン内のオブジェクトを識別するためのリレーションシップ機能を提供します。
つまりは、これをつかうとPrimをグループでまとめるだけではなく
Namespaceに関係なくオブジェクトをコントロールできるようになります。

やってみる

まずはサンプルを用意します。

このようなシンプルなレイヤーを用意します。

1
2
3
4
# Collectionを作る
collection = stage.DefinePrim("/collectionSample")
collectionName = "sampleCollection"
api = Usd.CollectionAPI.Apply(collection,collectionName)

そして、Collectionを作成したいPrimに
UsdCollectionAPIを利用してCollectionを適応します。

1
2
3
4
5
6
7
#usda 1.0

def "collectionSample" (
    prepend apiSchemas = ["CollectionAPI:sampleCollection"]
)
{
}

適応できました。
ですが、これだけだとまだからのSetを用意したにすぎないので
Primを指定してみます。

1
api.IncludePath(Sdf.Path("/World/SamplePrims/Cube"))

1
2
3
4
5
6
7
8
#usda 1.0

def "collectionSample" (
    prepend apiSchemas = ["CollectionAPI:sampleCollection"]
)
{
    prepend rel collection:sampleCollection:includes = </World/SamplePrims/Cube>
}

追加されました。
指定したPrimへのリレーションに、IncludePathが追加されたのがわかります。

Collectionを追加すると、追加したPrimに対して「collection」のNamespace以下に
プロパティが作成されます。
そして、このプロパティ名にはCollection名(上の例なら sampleCollection )が付き
そのコレクションごとのプロパティを追加するためのNamespaceが提供されます。
プロパティ以下にCollection名が入ることで、
1つのPrimに対して複数のCollectionが追加できるようになるわけですね。

Primの取得

Collectionに入れたPrimの取得方法

1
print(api.GetIncludesRel().GetTargets())

IncludePathの指定は、リレーションで定義されているので、
CollectionAPIのGetIncludesRelでリレーションを取得すると
かんたんにCollectionに含まれているPrimを取得することができます。

ExcludePathとExpansionRule

上の例だと、IncludePathを指定することでCollectionにPrimを入れることができました。
ですが、IncludePathとして指定したPrimだけではなく
その子Primも含めて取得したい場合もありますし、
その子Primのうち「除外したいPrim」も指定したいことがあるかとおもいます。

そうした時はExcludePath(除外指定)と、ExpansionRule(どのように展開するか)
を指定した上で、ComputeMembershipQueryを使うことで
Collectionに含まれるPrimを取得することができます。

1
api.ExcludePath(Sdf.Path("/World/SamplePrims/Cube/ExcludeCube"))

まずは、サンプルのレイヤーのうち、Cube/ExcludeCube以下を除外するようにします。

1
2
expansionRule = api.CreateExpansionRuleAttr()
expansionRule.Set("expandPrims")

そしてExpansionRuleを指定します。
これが、指定Prim以下の子すべてなのかだったり、そのPrimのみ指定だったりといった
選択をどのように展開するかを指定するアトリビュートになります。

name
explicitOnly IncludePathのみで子Primは含めない
expandPrims IncludePath以下の子Primも含める
expandPrimsAndProperties Includepath以下の子Primとアトリビュートも含める

選択肢はこの3つです。

次に、このCollectionを利用してPrimを取得します。

1
2
3
query = api.ComputeMembershipQuery()
# expandPrimsで指定されてるので、IncludePath以下にありExcludeに含まれないPrimがリストされる
print(Usd.CollectionAPI.ComputeIncludedObjects(query,stage))

apiからComputeMembershipQueryで、検査くるためのQueryを取得します。
そして、それを利用してComputeIncludeObjectsを実行すると
引数で指定したstage内のうち、Collectionに該当するPrimを取得できます。

1
[Usd.Prim(</World/SamplePrims/Cube>), Usd.Prim(</World/SamplePrims/Cube/pCube1>), Usd.Prim(</World/SamplePrims/Cube/pCube3>)]

結果、ExcludePathで指定したExcludeCubeとpCube2のPrimは除外され
それ以外の結果が取得できました。

1
expansionRule.Set("explicitOnly")

これを explicitOnlyに変えると、
1
[Usd.Prim(</World/SamplePrims/Cube>)]

子以下は含まれなくなりました。

1
expansionRule.Set("expandPrimsAndProperties")

最後に、Propertiesまで展開するとどうなるかというと

Attributeまでふくめてすべて取得することができました。

このExpansionRuleは、MembershipQueryの

1
print(query.GetAsPathExpansionRuleMap())

ExpansionRuleMapで確認することができて、このRuleMapに従って
ステージ内のPrimを「コレクション」することができます。

PathがCollectionに含まれるかどうか調べる

以上のやりかたでCollectionに含むPrimを取得することができましたが
あるSdfPathがCollectionに含まれているかを知りたい...といったケースも
発生するかとおもいます。

その時は、ComputeMembershipQueryを利用して

1
2
3
4
# 引数で指定したSdfPathがCollectionに含まれるか
print(query.IsPathIncluded("/World/SamplePrims/Cube/pCube1"))
# 除外されたPrimの場合
print(query.IsPathIncluded("/World/SamplePrims/Cube/ExcludeCube/pCube2"))

このようにPathが含まれるかをチェックすることができます。

Houdini

コードとusdaだけだとわかりにくいので、同様のことをHoudiniSOLARISで試してみます。

LOPにはCollectionノードが存在しているので、ノードを作成します。

DefaultPrimitivePathは、Collectionを追加したいPathを指定します。
そしてその下にCollectionに入れる条件を指定します。

上の例だと、青枠をCollectionに入れて、そのうち赤枠部分は除外
ExpansionRuleは Cube以下の子Prim全てを入れるようにしました。

Collectionが作れているかをPruneノードを使用して確認してみます。
Pruneは、 PrimitivePattern で指定したPrimを非表示状態にします。

PrimitivePatternにはCollectionを指定することもできるので、
カーソルボタンを押してCollectionを指定すると

結果。
Collectionに含まれている pCube2 以外のPrimが非表示になりました。

最初に説明したとおり、IncludePathとExcludePath、そしてExpansionRuleによって
Collectionに含まれるPrimが計算され
その結果によってPruneノードが実行されました。
Pruneにも同じような TargetPrimitivesの指定がある(Collectionを作る機能もある)のですが
挙動・指定方法は、USDのCollectionと同様になります。

まとめ

Collectionを使用すれば、IncludePath/ExcludePath/ExpansionRuleを組み合わせることで
単純なリレーションよりも、より手軽にステージ内のPrimにアクセスできるように
なることがわかりました。

これを使って、指定のPrimに自動で処理をさせたり
自分のやりたいシーングラフを表現できるようになるので、よりいっそうUSDで
できることの幅が広がりそうです。

https://fereria.github.io/reincarnation_tech/60_JupyterNotebook/USD/USDCollectoinSample2
Pythonでの操作方法は↑のNotebookで色々試してるので参考にしてください。