Skip to main content

0から始めるUSDPython(2) ステージを検索しよう

前回 で USD を Python で開いて、指定の Prim の Attribute を編集して 保存するという処理を書いてみましたが 多くの場合、Prim を固定パスで取得して何か編集する…というよりも、 ステージに含まれる特定の条件の Prim にたいしてなにか処理をすることのほうが多いと思います。

今回は、 USD のステージを検索(Traverse)して条件にマッチした Prim に対して処理を実行する ようにしてみます。

全ノード検索

UsdStage には、現在のステージにある Prim すべてを取得できるイテレーターが用意されていますので 自前で再帰処理を書かなくても簡単に書けます。 それが UsdStage の TraverseAll() です。 ので、まず前回も使用した Kitchen_set.usd を使用して すべてのノードをプリントしてみます。

from pxr import  Usd

stage = Usd.Stage.Open("D:/Kitchen_set/Kitchen_set.usd")

for prim in stage.TraverseAll():
print(prim)

実行すると、このようにシーンに含まれる Prim が大量にプリントされるかと思います。

Attribute の値が条件に合致している場合に何かしたい

これだと、ただ全 Prim を for で繰り返ししているだけでなにもしていないので ここで前回非表示にしたノードを print するようにしてみます。

# シーンにあるPrimの数だけ繰り返す
for prim in stage.TraverseAll():
if prim.GetAttribute('visibility').Get() == 'invisible':
print(prim)

Attribute に値をセットするときは .Set(Value) としていましたが、 Get() すると、Attribute の値を取得できます。 ので、非表示の場合( visibility が invisible の Attribute の Prim を取得する場合は 上のように if 文を書けば、指定の Prim にだけ処理をするというのが 書けるようになります。

では、処理をしたい Prim が if 文を使用することで取得することができたので、 非表示にした Attribute を表示して、上書き保存してみます。

from pxr import  Usd

stage = Usd.Stage.Open("D:/Kitchen_set/Kitchen_set.usd")

for prim in stage.TraverseAll():
if prim.GetAttribute('visibility').Get() == 'invisible':
prim.GetAttribute("visibility").Set("inherited")

stage.GetRootLayer().Save()

値を変更するときは、GetAttribute(AttributeName).Set(Value) とすればよいので 致した Prim に対して値をセットするにはこのように書けば OK です。

指定の Type に対して処理をしたい

条件は、これ以外にもいろいろと作ることができます。 ので、別の例で「指定の Prim のタイプ(スキーマ)のみ処理をする」というのを 書いてみます。

USD の Prim には、「スキーマ」と呼ばれる型が定義されています。 これは、いわゆる Maya のノードタイプ(Mesh や Transform 等)のように この Prim がどのようにふるまうのかを定義するものです。

サンプルの Kitchen_set のカップのモデルは、Mesh だったり 移動をするための Group は Xform だったり、

ライトだと、 DistantLight SphereLight DiskLight のように 3DCG で使用する各種データごとにこの Prim が指定されています。

なので、たとえば「シーンにある SphereLight に対して何かをしたい、値を取得したい」 だったり、「シーンにある Mesh に対してなにかしたい」のように 型ごとに処理を分けたい場合はこの Type を使用すればできます。

今回は、Kitchen_set に含まれる Mesh Prim に対して実行したい場合を書いてみます。

for prim in stage.TraverseAll():
if prim.GetTypeName() == "Mesh":
#何かしらの処理
pass

prim がどのスキーマを使用しているのかは、 UsdPrim.GetTypeName()で取得できます。 基本は Attribute で条件を指定していたところを GetTypeName を実行したい Type で 条件指定するのに変えただけです。

まとめ

これで、Path を固定することなく USD のステージ上に含まれる「何かしらの条件」にだけ 実行するといった処理が書けるようになりました。

複雑な条件だと、多少工夫する必要はありますが(特定のマテリアルにアサインされている Mesh だけ等) 基本はこの for prim in stage.TraverseAll() を使用することで USD のステージにある特定の Prim(ノード)に何かをするということが書けるようになります。

今回紹介した GetAttribute や GetTypeName 以外にも たとえば、指定の Attribute がある場合なら ( UsdPrim.HasAttribute() ) バリアントセットが指定されている場合 ( UsdPrim.HasVariantSets() )のように UsdPrim のドキュメントをを見ると、ほかの条件でも検索を書けると思うので 試しに別の条件で Prim を検索を試してみると良いかもしれません。

次回、Prim 作成編に続く。