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

PopulationMask(OpenMasked)について

Universal Scene Description 5 日目は、USD のファイルオープンの 機能の1つ、PopulationMask(OpenMasked)について紹介します。

USD は、コンポジションを使用することで巨大なシーンを扱うことができますが、 巨大なシーンを毎回すべて開くと時間がかかるので 指定した一部分だけをロードしたい...ということが多々あります。

その場合、Payload を使用してアンロードしておいた状態から指定 Prim をロードする事もできますが それ以外にも UsdStagePopulationMask という機能を使用することで 部分的なロードができるようになります。

使い方

まず、普通にロードした場合。

from pxr import Usd

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

Usd.Stage.Open(ファイルパス)をすることで、ロードすることができます。 この場合は、すべての Prim がロードされます。

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

次に Unload 状態でロードした場合。 この場合は、すべての Payload がアンロードされた状態になります。

では、実際に PopulationMask を使用した場合について。

Kitchen_set のうち、冷蔵庫だけをロードしてみます。

mask = Usd.StagePopulationMask().Add('/Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1')
stage = Usd.Stage.OpenMasked(r"D:/Kitchen_set/Kitchen_set.usd",mask)

この場合は、ロードしたい SdfPath を PopulationMask に追加して Usd.Stage.Open のかわりに OpenMasked を使用します。 こうすると、 冷蔵庫の指定 Path 以下にある Prim だけがロードされます。

usdview D:\Kitchen_set\Kitchen_set.usd --mask /Kitchen_set/Props_grp/North_grp/FridgeArea_grp/Refridgerator_1

PopulationMask は usdview で使用することができて、引数に --mask PrimPath を追加すれば 指定の Path 以下の Prim だけロードされた状態になります。

現在の Stage の PopulationMask を取得

次に、取得方法。

mask = stage.GetPopulationMask()
for path in mask.GetPaths():
print(path)

現在の Stage の PopulationMask がどうなっているか、またどんな Path が含まれているのかも確認が可能です。

PopulationMask を変更する

PopulationMask はロード時だけではなく、ロード後にも変更ができます。

#usda 1.0

def "a"{}
def "b"{}
def "c"{}

このようなシンプルな USD ファイルを用意して、 sample.usda という名前で保存しておきます。

mask = Usd.StagePopulationMask(['/a'])
stage = Usd.Stage.OpenMasked("D:/sample.usda",mask)
print(stage.ExportToString())
maskB = Usd.StagePopulationMask(['/b'])
stage.SetPopulationMask(maskB)
print(stage.ExportToString())

最初に a Prim だけを PopulationMask を使用してロードしたときは、Prim は a のみになります。 そのあと、 b Prim の PopulationMask をセットすると Stage は再構築され、b のみロードされたシーンになります。

PopulationMask のさらなる使い方

PopulationMask を使用すれば Stage の一部だけをロードできることがわかりました。

今までは、Add 等で1つあるいは複数の Path を追加するだけの使い方でしたが、 PopulationMask は、それ以外にも SdfPath を Set(集合)として扱うことができます。

先度帆の simple.usda で動作をみていきます。

このファイルのうち、 a Prim だけをロードしたい場合は、

mask = Usd.StagePopulationMask().Add('/a')
stage = Usd.Stage.OpenMasked("D:/sample.usda",mask)
print(stage.ExportToString())

このように、 a を PopulationMask に入れて OpenMasked で開けば OK です。

複数の SdfPath を指定する場合

mask = Usd.StagePopulationMask().Add('/a')
mask.Add('/b')

# あるいは
mask = Usd.StagePopulationMask(['/a','/b'])

複数の場合は、StagePopulationMask の引数に配列で指定するか、 PopulationMask に Add することで複数指定が可能です。

複数の PopulationMask から新しい PopulationMask を作る場合

# 複数の異なるMaskを結合する場合
maskA = Usd.StagePopulationMask().Add('/a')
maskB = Usd.StagePopulationMask().Add('/b')
# PopulationMaskを結合
union = Usd.StagePopulationMask().Union(maskA,maskB)
# これでもOK
maskA.GetUnion(maskB)

両方の PopulationMask に含まれる SdfPath のみにしたい

maskA = Usd.StagePopulationMask(['/a','/b'])
maskB = Usd.StagePopulationMask(['/c','/b'])
print(Usd.StagePopulationMask().Intersection(maskA,maskB))

指定の SdfPath を含むか確認したい

maskA = Usd.StagePopulationMask(['/a','/b'])
maskB = Usd.StagePopulationMask(['/b'])
print(maskA.Includes(maskB))

このように、すでにある PopulationMask を組み合わせることで別の PopulationMask を作成すれば 柔軟にシーンの部分ロードが可能になります。

まとめ

Payload をすることで大規模なシーンでも一部だけロードする...といったことが可能でしたが PopulationMask を使用すると、さらに細かく SdfPath を個別に指定しながら一部だけのロードが可能になります。 また、PopulationMask は、Sets のような使い方ができるので これを利用して様々な条件でも柔軟に部分ロードができます。

巨大なシーンを扱う場合、一部だけ修正・確認をしたいような場合にぜひお試しください。