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

Pythonで作るUSDアセット

Universal Scene Description AdventCalendar2021 20 日目は、 以前紹介した ComponentBuilderで遊ぼうに近い内容を Python でやりながら Python を使用した USD のコンポジションの作り方を説明していきます。

最終的な構成​

まず、最終的にどのようになるのかを見てみます。

今回はマテリアル回りは省いて、ジオメトリのみの構成です。 Kitchen_set の構造をベースにしつつ、ジオメトリのヴァリエーションは個別のレイヤーに分けつつ Payload の構造と、Inherits の構造をデフォルトで仕込むようにします。

では、順番に処理を見ていきます。

アセット名の指定など​

from pxr import Usd,Sdf,Ar
import glob
import shutil
import os

まずは必用なモジュールを Import します。

ASSETS_DIR = "D:/sample/assets"

そして Asset のルートディレクトリを決めておきます。

各アセット以下はこのような構成になるようにします。 Prim やフォルダ名、レイヤー名などには、AssetName を使用するので 事前に変数で定義しておきます。 (実際に使用する場合は、この辺りは関数にしたほうが良いけど、今回はベタ書きします)

# Asset名を決める
assetName = "sampleAssets"
version = 1.0

assetDir = f"{ASSETS_DIR}/{assetName}"

ディレクトリは決まったので、USD の Prim を作っていきます。 最初に、 payload のレイヤーを作り、その中にすでにあるジオメトリのレイヤーを リファレンスするようにします。

payloadStage = Usd.Stage.CreateInMemory()
payloadsLayer = payloadStage.GetRootLayer()
prim = payloadStage.DefinePrim(f'/{assetName}')
payloadStage.SetDefaultPrim(prim)
rootPath = prim.GetPath()

CreateInMemory で、Stage を作り、空の Prim の作成+ DefaultPrim の設定をします。 新しいレイヤーを作る場合は、いくつかやり方があります。

stage = Usd.Stage.CreateNew(f"{assetDir}/{assetName}.payload.usd")

このように、CreateNew する手もありますが この場合既にファイルがあるとエラーになるので、

payloadLayer = Sdf.Layer.FindOrOpen(f"{assetDir}/{assetName}.payload.usd")
pyaloadStage = Usd.Stage.Open(payloadLayer)

FindOrOpen するか、サンプルのように CreateInMemory しておくほうが個人的には好きです。 (CreateInMemory なら、必ず作り直すのでアセットづくりの場合なおのこと。)

Variant 作り​

geomVariantDir = "D:/sample/variant"

# Variantを指定する
vset = prim.GetVariantSets().AddVariantSet('assets')
geomPath = rootPath.AppendChild('Geom')
geomPrim = payloadStage.DefinePrim(geomPath)
payloadStage.DefinePrim(geomPath)

variantDir = f"{assetDir}/variant"
os.makedirs(variantDir,exist_ok=True)

# 指定フォルダ以下にあるレイヤーを、VariantSetとして追加する
for f in glob.glob(f"{geomVariantDir}/*.usd*"):
# Assets以下にコピーする
basename = os.path.basename(f)
shutil.copy2(f,f"{variantDir}/{basename}")
variantName = os.path.splitext(basename)[0]
vset.AddVariant(variantName)
# モデルパターンの切り替え用のVariantSetを作る
vset.SetVariantSelection(variantName)
with vset.GetVariantEditContext():
# variant 以下のモデルをReferenceする
geomPrim.GetReferences().AddReference(f"./variant/{basename}")

payloadsLayer.Export(f"{assetDir}/{assetName}.payload.usd")

Payload 用の Stage ができたら、その中に VariantSet を作り、 ジオメトリのレイヤーを VariantSet で切り替えできるようにします。

今回は、指定フォルダ以下にあるレイヤーを切り替えできるようにする 感じで処理をするので、モデルの置き場所を指定して Asset 以下にコピーしたうえで VariantSet を作ります。 (この辺りはお好みで)

実行すると、このようなレイヤーが出来上がります。

payload.usd を usdview で確認すると、こんな感じになります。 RootPrim に VariantSet が追加され、指定フォルダ以下の Layer が Variant で切り替えできるようになります。

Inherits 作り​

次に Inherits するためのレイヤーを用意します。 Reference は指定 Prim に対して Reference する Layer の Path(あるいは SdfPath)を指定しますが Inherits は、SdfPath を指定します。 そのため、Inherits 用の ClassPrim を別レイヤー化したい場合は、 SubLayer と組み合わせる必要があります。

# Inheritsを作る
inheritsStage = Usd.Stage.CreateInMemory()
inheritsLayer = inheritsStage.GetRootLayer()
inheritsStage.CreateClassPrim("/__class__")
inheritsLayer.Export(f"{assetDir}/{assetName}.class.usd")

こんな感じで、 class ( Specifier は class ) だけを定義した別レイヤーを作成します。 このように分けておけば、あとで継承した Prim に対して何かしたい場合は このレイヤーを編集すれば OK になります。

メインの Layer を作る​

最後に、実際にレイアウトなどで配置するときに読み込む Layer を作ります。 レイヤー名は、アセット名になるようにして これまで作成した Layer を読み込みつつ、AssetInfo と Kind を指定します。

# Assetsのレイヤーをつくる
stage = Usd.Stage.CreateInMemory()
layer = stage.GetRootLayer()
# そして、AssetsのRoodPrimを作成する
prim = stage.DefinePrim(f'/{assetName}')
rootPath = prim.GetPath()
# Kindを指定
Usd.ModelAPI(prim).SetKind('component')
stage.SetDefaultPrim(prim)

# assetName.usd にはAssetInfoを指定する
assetInfo = {
"identifier":f"./{assetName}/{assetName}.usd",
"name":assetName,
'version':version
}
prim.SetAssetInfo(assetInfo)
# Variantを入れた payload Layer を Payloadする
prim.GetPayloads().AddPayload(f"{assetDir}/{assetName}.payload.usd")

# Inheritsの構造を仕込む
layer.subLayerPaths = [f'./{assetName}.class.usd']
prim.GetInherits().AddInherit('/__class__')

layer.Export(f"{assetDir}/{assetName}.usd")

完成した USD ファイルを usdview で開いてみます。 Composition を見ると、Root になる sampleAssets には SubLayer Inherits Payload Variant Geom には Reference と、(Specialize を除いた)5つのコンポジションアークを使用した アセットが出来上がりました。

Meta Data を確認すると、 variant assetInfo kind が指定されています。

まとめ​

以上、Python を使用して Asset のセットアップでした。 このように Python で書くと、どこで何をして、最終的にどうなるのかが わかりやすくなるのではと思います。 https://fereria.github.io/reincarnation_tech/60_JupyterNotebook/USD/CompArc/usd-comp-arc/ 今回は Notebook で書いたのですが、実際に使う場合は 関数化して、コマンドラインツール化して各種自動化と組み合わせると良いかと思います。 公式のリポジトリの

USD/extras/usd/examples/usdMakeFileVariantModelAsset/usdMakeFileVariantModelAsset.py

に、今回書いた内容のコマンドラインツールのサンプルがあるので 合わせて確認してみてください。