コンテンツにスキップ

Pythonで作るUSDアセット

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

最終的な構成

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

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

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

アセット名の指定など

1
2
3
4
from pxr import Usd,Sdf,Ar
import glob
import shutil
import os

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

1
ASSETS_DIR = "D:/sample/assets"

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

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

1
2
3
4
5
# Asset名を決める
assetName = "sampleAssets"
version = 1.0

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

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

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

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

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

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

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

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

Variant 作り

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 と組み合わせる必要があります。

1
2
3
4
5
# 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 を指定します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 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

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


最終更新日: 2022-07-12 16:29:57