USDのInstanceについて
USD のインスタンス化は、「同じ」オブジェクトの多数のインスタンスが UsdStage 上で同じ Prim を共有することができる機能です。
Instancing in USD is a feature that allows many instances of “the same” object to share the same representation (composed prims) on a UsdStage. 参考: https://graphics.pixar.com/usd/release/glossary.html#usdglossary-instancing
インスタンスを使用すると、インスタンス以下の Prim をオーバーライドすることができなくなる代わりに UsdStage を処理する時に、(同じモデルを参照することで)ロードの高速化やメモリの省略を することができます。
Instance を作る
#usda 1.0
(
defaultPrim = "geom"
)
def Xform "geom"{
def Cube "cube" ()
{
}
}
このような Cube.usd を用意します。 インスタンス用のアセットは、Root に XformPrim を作成し、 その子に Mesh を置きます。 (RootPrim が Mesh ではいけない)
今回は、DefaultPrim の子供にシンプルな Cube 1つを置いた構造になっています。
#usda 1.0
def "sampleA" (
instanceable = true
prepend references = @./cube.usd@
)
{
}
def "sampleB" (
instanceable = true
prepend references = @./cube.usd@
)
{
}
def "sampleC" (
prepend references = @./cube.usd@
)
{
}
このようにリファレンスで読み込みます。 そして sampleA sampleB には instanceable を入れて、sampleC には instancealbe を入れません。
usdview で表示すると、このようになります。
図に表すとこのようになります。
Prim に対して instanceable を入れると、同じインスタンスオブジェクトごとに「Prototype」と呼ばれるインスタンスの ベースになる Prim を1つだけ生成し、インスタンスする Prim との関係性を記録します。 usdview では Prototype は表示されていませんが、
stage.GetPrototypes()
[Usd.Prim(</__Prototype_1>)]
このように、Stage の GetPrototypes 関数を使用すると instanceable の Prim の PrototypePrim を確認することができます。
prototypePrim はこのようになります。 インスタンスを使用しない場合、リファレンス先の Prim はリファレンスしている Prim 以下に展開されますが インスタンスの場合は、このようにルート以下に見えない Prim として展開されます。
# Instanceの場合はChildはみつからない
print(primB.GetChildren())
# > []
# 普通なら見つかる
print(primC.GetChildren())
# > [Usd.Prim(</sampleC/cube>)]
そのため、 instanbeable な Prim に GetChildren() してみると Instance の時は個 Prim が見つからず(本体は Prototype 以 下なので) 通常の場合は GetChildren で個 Prim を取得できるようになります。
!!! info
_Prototype## の数字は固定ではなく動的に決まります。 なので、この数字を当てにして処理を書くことはできません。
Prototype からインスタンスを取得する
prototype = primA.GetPrototype()
for instance in prototype.GetInstances():
print(instance)
instanceable なオブジェクトを Prototype として展開すると 配置されたオブジェクトは1つの Prototype を共有します。 _Prototype## の Prim 名は毎回変わりますが、この Prototype がどの Instance のオブジェクトなのかは Prim から GetInstances で取得することができます。
これを利用すれば、実際にどのオブジェクトとして配置したのかを把握することができます。