UsdCollectionを使おう
USD の「Collection」とは、Maya の Sets と似た機能で USD シーン内のオブジェクトを識別するためのリレーションシップ機能を提供します。 つまりは、これをつかうと Prim をグループでまとめるだけではなく Namespace に関係なくオブジェクトをコントロールできるようになります。
やってみる
まずはサンプルを用意します。
このようなシンプルなレイヤーを用意します。
# Collectionを作る
collection = stage.DefinePrim("/collectionSample")
collectionName = "sampleCollection"
api = Usd.CollectionAPI.Apply(collection,collectionName)
そして、Collection を作成したい Prim に UsdCollectionAPI を利用して Collection を適応します。
#usda 1.0
def "collectionSample" (
prepend apiSchemas = ["CollectionAPI:sampleCollection"]
)
{
}
適応できました。 ですが、これだけだとまだからの Set を用意したにすぎないので Prim を指定してみます。
api.IncludePath(Sdf.Path("/World/SamplePrims/Cube"))
#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 の取得方法
print(api.GetIncludesRel().GetTargets())
IncludePath の指定は、リレーションで定義されているので、 CollectionAPI の GetIncludesRel でリレーションを取得すると かんたんに Collection に含まれている Prim を取得することができます。
ExcludePath と ExpansionRule
上の例だと、IncludePath を指定することで Collection に Prim を入れることができました。 ですが、IncludePath として指定した Prim だけではなく その子 Prim も含めて取得したい場合もありますし、 その子 Prim のうち「除外したい Prim」も指定したいことがあるかとおもいます。
そうした時は ExcludePath(除外指定)と、ExpansionRule(どのように展開するか) を指定した上で、ComputeMembershipQuery を使うことで Collection に含まれる Prim を取得することができます。
api.ExcludePath(Sdf.Path("/World/SamplePrims/Cube/ExcludeCube"))
まずは、サンプルのレイヤーのうち、Cube/ExcludeCube 以下を除外するようにします。
expansionRule = api.CreateExpansionRuleAttr()
expansionRule.Set("expandPrims")
そして ExpansionRule を指定します。 これが、指定 Prim 以下の子すべてなのかだったり、その Prim のみ指定だったりといった 選択をどのように展開するかを指定するアトリビュートになります。
name | |
---|---|
explicitOnly | IncludePath のみで子 Prim は含めない |
expandPrims | IncludePath 以下の子 Prim も含める |
expandPrimsAndProperties | Includepath 以下の子 Prim とアトリビュートも含める |
選択肢はこの3つです。
次に、この Collection を利用して Prim を取得します。
query = api.ComputeMembershipQuery()
# expandPrimsで指定されてるので、IncludePath以下にありExcludeに含まれないPrimがリストされる
print(Usd.CollectionAPI.ComputeIncludedObjects(query,stage))
api から ComputeMembershipQuery で、検査くるための Query を取得します。 そして 、それを利用して ComputeIncludeObjects を実行すると 引数で指定した stage 内のうち、Collection に該当する Prim を取得できます。
[Usd.Prim(</World/SamplePrims/Cube>), Usd.Prim(</World/SamplePrims/Cube/pCube1>), Usd.Prim(</World/SamplePrims/Cube/pCube3>)]
結果、ExcludePath で指定した ExcludeCube と pCube2 の Prim は除外され それ以外の結果が取得できました。
expansionRule.Set("explicitOnly")
これを explicitOnly に変えると、
[Usd.Prim(</World/SamplePrims/Cube>)]
子以下は含まれなくなりました。
expansionRule.Set("expandPrimsAndProperties")
最後に、Properties まで展開するとどうなるかというと Attribute までふくめてすべて取得することができました。
この ExpansionRule は、MembershipQuery の
print(query.GetAsPathExpansionRuleMap())
ExpansionRuleMap で確認することができて、この RuleMap に従って ステージ内の Prim を「コレクション」することができます。
Path が Collection に含まれるかどうか調べる
以上のやりかたで Collection に含む Prim を取得することができましたが ある SdfPath が Collection に含まれているかを知りたい...といったケースも 発生するかとおもいます。
その時は、ComputeMembershipQuery を利用して
# 引数で指定したSdfPathがCollectionに含まれるか
print(query.IsPathIncluded("/World/SamplePrims/Cube/pCube1"))
# 除外されたPrimの場合
print(query.IsPathIncluded("/World/SamplePrims/Cube/ExcludeCube/pCube2"))
このように Path が含まれるかをチェックすることができます。