今回から,USD ファイルを出力する Python のコードをプログラミングしていきます。
教材
USD については,あんどうめぐみ@れみりあ さんによる非常にわかりやすい解説記事があります。
この記事に挙がっている USD を Python のコードで生成しながら,USD の仕組みと Python インターフェースの両方を同時に勉強していくことにします。
コンポジションアーク
繰り返しになりますが,あんどうめぐみ@れみりあ さんによる次の記事内容をフォローするためのプログラムを書いていきます。今回はこれ。「コンポジションアークとは」です。
元記事の「ひとつの usda ファイル内に継承元のクラスとそれを継承したプリムがあり、それら両方に値がセットされている」例に取り組みます。
CreateAttribute() を使って testValue を 2 箇所に定義しています。継承は,GetInherits().AddInherit() として実現します。
from pxr import Usd, Sdf
stage = Usd.Stage.CreateInMemory()
layer = stage.GetRootLayer()
# "TestClass"
cls = stage.CreateClassPrim('/TestClass')
cls.CreateAttribute('testValue', Sdf.ValueTypeNames.Bool).Set(False)
clsPath = cls.GetPath()
# "Hoge"
hoge = stage.DefinePrim('/Hoge')
hogePath = hoge.GetPath()
# "Hoge/Fuga"
fuga = stage.DefinePrim(f'{hogePath}/Fuga')
fuga.GetInherits().AddInherit(clsPath)
fuga.CreateAttribute('testValue', Sdf.ValueTypeNames.Bool).Set(True)
layer.Export('./Sample_1.usda')
USD ファイルを確認してみます。
#usda 1.0
class "TestClass"
{
custom bool testValue = 0
}
def "Hoge"
{
def "Fuga" (
prepend inherits = </TestClass>
)
{
custom bool testValue = 1
}
}
合成結果を見てみます。usdcat に --flatten オプションをつけて実行します。testValue は 1 となっており,「LIVRPSの原則」に従ってローカルが優先されていることが確認できます。
usdcat --flatten Sample_1.usda
#usda 1.0
(
doc = """Generated from Composed Stage of root layer /home/kagei/USD/myLearn/Reincarnation/01_composition/Sample_2.usda
"""
)
class "TestClass"
{
custom bool testValue = 0
}
def "Hoge"
{
def "Fuga"
{
custom bool testValue = 1
}
}
次に,参照(References)を追加した場合を試してみます。同様に,教材に挙がっている USD のサンプルを生成してみます。Reference_A.usda に defaultPrim がセット(SetDefaultPrim)されていることに注目します。これは,参照元にどのプリムを参照させるか伝えるために必要とされるものです。
from pxr import Usd, Sdf
stage = Usd.Stage.CreateInMemory()
layer = stage.GetRootLayer()
# "TestClass"
cls = stage.CreateClassPrim('/TestClass')
cls.CreateAttribute('testValue', Sdf.ValueTypeNames.Int).Set(100)
layer.Export('./Class.usda')
from pxr import Usd, Sdf
stage = Usd.Stage.CreateInMemory()
layer = stage.GetRootLayer()
# "Hoge" (DefaultPrim)
hoge = stage.DefinePrim('/Hoge')
stage.SetDefaultPrim(hoge)
hogePath = hoge.GetPath()
# "Hoge/Fuga"
fuga = stage.DefinePrim(f'{hogePath}/Fuga')
fuga.CreateAttribute('testValue', Sdf.ValueTypeNames.Int).Set(10)
layer.Export('./Reference_A.usda')
Reference_A.usda を参照する USD を生成します。参照は,GetReferences().AddReference() で実現されます。引数に与えるのは USD 名(Reference_A.usda)ですが,先述の defaultPrim によって参照先のプリムが見つけられるという算段です。
from pxr import Usd
stage = Usd.Stage.CreateInMemory()
layer = stage.GetRootLayer()
# subLayerPaths
layer.subLayerPaths = ['./Class.usda']
# "Hoge"
hoge = stage.DefinePrim('/Hoge')
hogePath = hoge.GetPath()
hoge.GetReferences().AddReference('./Reference_A.usda')
# "Hoge/Fuga"
fuga = stage.DefinePrim(f'{hogePath}/Fuga')
fuga.GetInherits().AddInherit('/TestClass')
layer.Export('Sample_2.usda')
生成された USD を確認してみましょう。
#usda 1.0
class "TestClass"
{
custom int testValue = 100
}
#usda 1.0
(
defaultPrim = "Hoge"
)
def "Hoge"
{
def "Fuga"
{
custom int testValue = 10
}
}
#usda 1.0
(
subLayers = [
@./Class.usda@
]
)
def "Hoge" (
prepend references = @./Reference_A.usda@
)
{
over "Fuga" (
prepend inherits = </TestClass>
)
{
}
}
合成結果を確認してみます。LIVRPS の原則によって References よりも Inherits の方が優先されるので,testValue = 100 が得られています。
usdcat --flatten Sample_2.usda
#usda 1.0
(
doc = """Generated from Composed Stage of root layer /home/kagei/USD/myLearn/Reincarnation/01_composition/Sample_4.usda
"""
)
class "TestClass"
{
custom int testValue = 100
}
def "Hoge"
{
def "Fuga"
{
custom int testValue = 100
}
}
まとめ
今回はコンポジションアークに関わる「継承」と「参照」を学習しました。参照はレイヤ(USDファイル)のパス指定で行い,defaultPrim によってプリムパスを解決する、ということを覚えておきたいと思います。