Skip to content

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

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

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

全ノード検索

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

1
2
3
4
5
6
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 するようにしてみます。

1
2
3
4
# シーンにある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 を表示して、上書き保存してみます。

1
2
3
4
5
6
7
8
9
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 に対して実行したい場合を書いてみます。

1
2
3
4
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 作成編に続く。