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 のような使い方ができるので これを利用して様々な条件でも柔軟に部分ロードができます。
巨大なシーンを扱う場合、一部だけ修正・確認をしたいような場合にぜひお試しください。