コンテンツにスキップ

PythonUSD チートシート

Python を使用して USD を操作するやり方がだいぶ分かってきたので
よく使う物とかをまとめ。

全般

Import

1
2
import os.path
from pxr import Usd, UsdGeom, Sdf, Gf

Stage 関係

New シーン

1
stage = Usd.Stage.CreateInMemory()

usda を作らずにとりあえずステージを作る場合。

1
stage = Usd.Stage.CreateNew(USD_PATH_ROOT + '/HelloWorld.usda')

usda を作って、新しいステージを作る。

USD を開く

1
stage = Usd.Stage.Open(USD_PATH_ROOT + '/HelloWorld.usda')

すでにある USD ファイルをステージとして開く。

Payload をロードせずに USD を開く

1
stage = Usd.Stage.Open(USD_PATH_ROOT + '/HelloWorld.usda',Usd.Stage.LoadNone)

保存する

1
2
stage = Usd.Stage.CreateNew(USD_PATH_ROOT + '/HelloWorld.usda')
stage.Save()

開いている usd をそのまま保存。

1
2
stage = Usd.Stage.CreateInMemory()
stage.GetRootLayer().Export(USD_PATH_ROOT + '/HelloWorld.usda')

メモリ上のみで作成している USD を Export する。
CreateNew して開いて保存する場合、すでに USD があると Error になってしまうが
こちらの場合はエラーにならない。

現在の USD の中身を確認する

1
print(stage.GetRootLayer().ExportToString())

ExportToString をすると、げんざいの USD をプリントすることができる

全コンポ結果を反映した USD を確認する

1
stage.Flatten().ExporToString()

通常の ExportToString()の場合、コンポ情報が残った状態で表示される。
が、すべてのコンポジションの結果をすべて判定(Flatten)した状態で見たい場合は
上のようにする。
当然のことながら、複雑なコンポを行っている場合 Flatten するとファイルサイズは増大する。

Stage 関係

ステージ内の Prim をトラバースする

1
2
3
compStage = Usd.Stage.Open(USD_PATH_ROOT + "/sample.usda")
for prim in compStage.Traverse():
    print(prim)

実行すると、このようなシーングラフなら

このように全 Prim を深さ優先で取得することができる。

Payload がロードされていないノードも Traverse する

Prim の状態をチェックしつつ検索するには GetFilteredChildren を使用する。
このコマンドの場合は、引数に Traverse するノードの状態を指定することで
該当するノードを取得することができる。

1
2
for i in prim.GetFilteredChildren(Usd.PrimIsActive & Usd.PrimIsDefined & ~Usd.PrimIsAbstract):
    print(i)

通常の Traverse や GetChildren は、上のフラグに+して Usd.PrimIsLoaded も ON になっている。
なので、Payload で読まれていない Prim は取得できない。

Layer をミュートする

1
2
3
# Layerのusdファイルは identifer で取得できる
# パス指定でLayerをミュート(コンポ処理から除外)できる
compStage.MuteLayer(layer.identifier)

ミュートは現在のステージ上のみで有効で、USD ファイル内には保存されない。
→ ミュートした状態で Flatten すると、ミュート状態のレイヤーは無効化される。

Layer 関係

RootLayer を取得

1
2
openUsd = Usd.Stage.Open(USD_PATH + "/baseUSD.usda")
print(openUsd.GetRootLayer())

Composition の Root の Layer(.usda)を取得する。
ここで取得出来る Sdf.Find()で取得出来る Layer の Prim は
いわゆる PrimSpec。

指定 Layer オブジェクトの usd ファイルパスを取得する

1
print(layer.identifier)

Prim 操作

Prim/Class/Over を作る

1
2
3
stage.DefinePrim("/hogehoge")
stage.OverridePrim("/over")
stage.CreateClassPrim("/class")

スキーマなしの Prim が作成される。

Stage から Prim を取得する

1
2
prim = stage.GetPrimAtPath('/hogehoge')
print(prim)

スキーマありの Prim を定義する

1
2
3
4
5
stage = Usd.Stage.CreateInMemory()
# Xformを作る
xform = UsdGeom.Xform.Define(stage, '/xform')
# Cubeを作る
cube = UsdGeom.Cube.Define(stage, '/hello')

ConcreteSchema には Define 関数があるので、↑ のように定義する。

Schema オブジェクトから Prim を取得

1
prim = xform.GetPrim()

SdfPath 関係

SdfPath の基本操作

1
2
sdfPath = Sdf.Path("/base")
xform = UsdGeom.Xform.Define(stage, sdfPath)

SdfPath は、 / スタートで Stage 内のシーングラフを定義する。
定義した Path で、Prim やスキーマの定義を作ることができる。

各オブジェクトから Path 取得

1
2
3
attr = prim.CreateAttribute("test", Sdf.ValueTypeNames.Bool)
xformPath = xform.GetPrim().GetPath()
attrPath = attr.GetPath()

Path を取得したい Prim や Attribute、Prim オブジェクトで .GetPath() する。
Attribute の Path は /base.test のように . で表現される。

SdfPath が何を指しているか確認する

1
2
3
print(sdfPath.IsPropertyPath())
print(sdfPath.IsPrimPath())
print(sdfPath.IsTargetPath())

Is ~ Path  で、SdfPath が何をしてしているのかチェックできる。

SdfPath 操作

1
2
3
4
# 子に対して引数の階層を追加する
cldPath = sdfPath.AppendChild('hoge')
# 子に対してAttributeを追加する
cldAttrPath = sdfPath.AppendProperty('hogeAttr')

Attribute 操作

Attribute を作る/セットする

1
2
3
4
5
6
# Boolの場合
attr = prim.CreateAttribute("test", Sdf.ValueTypeNames.Bool)
attr.Set(False)
# Colorの場合
color_attr = prim.CreateAttribute("color", Sdf.ValueTypeNames.Color3d)
color_attr.Set(Gf.Vec3d(1, 1, 1))

ValueTypeNames での型指定方法は こちらを参照。
Color や Vector などの型は Gf モジュールにある定義を使用してセットする。

Attribute から値を取得する

1
2
attr = prim.GetAttribute('test')
print(attr.Get())

Namespace を使用する

1
2
3
4
# Namespaceつきのアトリビュートを作る
prim.CreateAttribute("ns:testVal", Sdf.ValueTypeNames.Bool)
props = prim.GetPropertiesInNamespace('ns')
print(props)

プロパティ名・アトリビュート名には Namespace をつけることができる。
つけかたは Namespace:hogehoge のように : で区切れば OK。
Namespace をつけておくと、GetPropertiesInNamespace 関数を使用して
指定の Namespace のプロパティやアトリビュートを取得することができる。

Namespace や Nmaespace 無しのプロパティ名を取得

1
2
3
print(attr.GetBaseName())
print(attr.GetNamespace())
print(attr.SplitName())

この Namespace やプロパティ名は、プロパティオブジェクトで取得することができる。

Relationship を使用する

Relationship を作成

1
2
3
4
5
6
7
# RelationshipでPrimを入れる
rel = prim.CreateRelationship('test')
rel.AddTarget(relSdfPath)
rel.AddTarget(relSdfPathB)
# AttributeもRelにできる
relAttr = prim.CreateRelationship('attr_test')
relAttr.AddTarget(attr.GetPath())

Relationship 先を取得

1
attrPath.GetTargets()

GetTargets()を使用すると、接続先の SdfPath を取得できる。

SdfPath から Attribute の値を取得する

1
2
relPrim = stage.GetObjectAtPath(attrPath.GetTargets()[0])
print(relPrim.Get())

SdfPath から Prim または Attribute を取得したい場合は、Stage の GetObjectAtPath()を使用する。
Object で取得したばあい、Prim の場合は Prim オブジェクトが帰ってくるし
Attribute だったら Attribute オブジェクトが帰ってくる。

Metadata

Metadata は Prim や Attribute などに対して設定できる付加情報。

Metadata の取得

1
2
# 指定のPrim・Attribute・PropertyのMetadataをDictで取得
print(prim.GetAllMetadata())

Metadata に値をセットする

1
newScn.SetMetadata('comment', 'Hello World')

CustomData を使用する

1
2
3
4
5
6
# 指定のオブジェクトに対してCustomDataを指定する
prim.SetCustomDataByKey('userCustomMeta', 'fuga')
# 取得する
print(prim.GetCustomData())
# namespaceを指定した場合
prim.SetCustomDataByKey('test:userCustomMeta', 'fuga')


CustomData で Namespace をつけると、Dict 型をネストできる。
val['test']['usercustomdata']
アクセスするときはこんな感じにできる。

Transforrm 操作

Xform オブジェクトを使用する場合

1
2
3
stage = Usd.Stage.CreateInMemory()
xform = UsdGeom.Xform.Define(stage, '/xform')
xform.AddTranslateOp().Set((50, 0, 0))

Xformable クラスに各種 Tranlsform 操作用の関数があるので
それを使用すれば Transform ができる。

Prim から Transform する場合

1
2
3
path = Sdf.Path("/xform")
prim = stage.GetPrimAtPath(path)
UsdGeom.XformCommonAPI(prim).SetRotate((90, 0, 0))

Xform オブジェクトではなく、Prim オブジェクトから
Transform 処理をしたい場合は XformCommonAPI を使用する。

コンポジション関係

VariantSet

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
vset = prim.GetVariantSets().AddVariantSet('hogehoge')
vset.AddVariant('red')
vset.AddVariant('blue')
vset.AddVariant('green')

colorAttr = UsdGeom.Gprim.Get(newScn, '/World/Cube').GetDisplayColorAttr()

vset.SetVariantSelection('red')
with vset.GetVariantEditContext():
    colorAttr.Set([(1, 0, 0)])

vset.SetVariantSelection('blue')
with vset.GetVariantEditContext():
    colorAttr.Set([(0, 0, 1)])

vset.SetVariantSelection('green')
with vset.GetVariantEditContext():
    colorAttr.Set([(0, 1, 0)])

Reference

1
2
refPrimA = stage.DefinePrim("/World/BookGrp/Book")
refPrimA.GetReferences().AddReference(kitchenSetRoot + 'Book/Book.usd')

Reference で読み込みたい usd を Prim に対してセットする

Inherits

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# クラスを定義して保存する
classPrim = stage.CreateClassPrim('/TestClass')
attr = classPrim.CreateAttribute('hoge', Sdf.ValueTypeNames.Bool)
attr.Set(True)
stage.GetRootLayer().Export(USD_PATH + 'usdClass.usda')

# 定義したクラスをSubLayerでロードして、継承する
inheritStage = Usd.Stage.CreateInMemory()
rootLayer = inheritStage.GetRootLayer()
rootLayer.subLayerPaths = [USD_PATH + 'usdClass.usda']

prim = inheritStage.DefinePrim('/hoge')
path  = Sdf.Path('/TestClass')
prim.GetInherits().AddInherit(path)

print(inheritStage.GetRootLayer().ExportToString())

継承したいクラスが別ファイルに存在する場合は
ファイルをサブレイヤーでロードして、それから継承先の Prim に対して
GetInherits().AddInherit(path)
で読み込む。

出力結果はこんな感じに。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#usda 1.0
(
    subLayers = [
        @C:/pyEnv/JupyterUSD_py27/usd/usdClass.usda@
    ]
)

def "hoge" (
    prepend inherits = </TestClass>
)
{
}

SubLayer

1
2
3
stage = Usd.Stage.CreateInMemory()
rootLayer = stage.GetRootLayer()
rootLayer.subLayerPaths = [kitchenSetRoot + "/Book/Book.usd", kitchenSetRoot + "/Ball/Ball.usd"]

アニメーション関係

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
newScn.SetStartTimeCode(0)
newScn.SetEndTimeCode(100)

# Mem上に作成したUSDファイルを色々コントロール
worldGeom = UsdGeom.Xform.Define(newScn, "/World")
cubeGeom = UsdGeom.Cube.Define(newScn, "/World/Cube")

# PrimのPath(sdfPath)の作成。
worldPath = Sdf.Path("/World")
helloPath = worldPath.AppendChild("hello")

# Cubeをアニメーション
spin = cubeGeom.AddRotateZOp(opSuffix='spin')
spin.Set(time=0, value=0)
spin.Set(time=100, value=360)

マテリアル関係

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
stage = Usd.Stage.CreateInMemory()
rootLayer = stage.GetRootLayer()

sphere = UsdGeom.Sphere.Define(stage, '/test/sphere')

matPath = Sdf.Path("/Model/Material/MyMat")
mat = UsdShade.Material.Define(stage, matPath)
shader = UsdShade.Shader.Define(stage, matPath.AppendChild('testShader'))

# Shaderのアトリビュート設定
# 色をつけただけの基本のPBRシェーダーを作る
shader.CreateIdAttr('UsdPreviewSurface')
shader.CreateInput('diffuseColor', Sdf.ValueTypeNames.Color3f).Set(Gf.Vec3f(0, 1, 0))
shader.CreateInput('metalic', Sdf.ValueTypeNames.Float).Set(0.9)
shader.CreateInput('roughness', Sdf.ValueTypeNames.Float).Set(0.2)
# Shaderの結果をMatにつなげる
mat.CreateSurfaceOutput().ConnectToSource(shader, "surface")

# Bind
UsdShade.MaterialBindingAPI(sphere.GetPrim()).Bind(mat)

Mesh 関係

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
UsdGeom.Xform.Define(stage, '/hoge')
mesh = UsdGeom.Mesh.Define(stage, '/hoge/hogehoge')

# %%

mesh.CreatePointsAttr([(-5, -5, 5), (5, -5, 5), (5, 5, 5), (-5, 5, 5)])
# 1Faceあたりの頂点数
mesh.CreateFaceVertexCountsAttr([3, 3])
# 結線情報?
mesh.CreateFaceVertexIndicesAttr([0, 1, 2, 0, 2, 3])
# BoundingBoxをセット?
mesh.CreateExtentAttr(UsdGeom.PointBased(mesh).ComputeExtent(mesh.GetPointsAttr().Get()))

Plugin 関係

ロードされている Plugin をリストする

1
2
3
4
for i in Plug.Registry().GetAllPlugins():
    print(i.name)
    print(i.path)
    print(i.resourcePath)