メインコンテンツまでスキップ

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
explicitOnlyIncludePath のみで子 Prim は含めない
expandPrimsIncludePath 以下の子 Prim も含める
expandPrimsAndPropertiesIncludepath 以下の子 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 が含まれるかをチェックすることができます。

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 で色々試してるので参考にしてください。