教材
USD については,あんどうめぐみ@れみりあ さんによる非常にわかりやすい解説記事があり
ます。
この記事に挙がっている USD を Python のコードで生成しながら,USD の仕組みと Python インターフェースの両方を同時に勉強していきます。
サブレイヤー
繰り返しになりますが,あんどうめぐみ@れみりあ さんによる次の記事内容をフォローするためのプログラムを書いていきます。今回はこれ。「サブレイヤーとは」です。
Base.usda(緑の玉)を出力する Python のコードです。
from pxr import Usd, Sdf, UsdGeom, UsdShade
stage = Usd.Stage.CreateInMemory()
layer = stage.GetRootLayer()
# Material
material = stage.DefinePrim('/Material')
materialPath = material.GetPath()
# Material/MyMaterial
myMaterial = UsdShade.Material.Define(stage, f'{materialPath}/MyMaterial')
myMaterialOutput = myMaterial.CreateOutput('surface', Sdf.ValueTypeNames.Token)
myMaterialPath = myMaterial.GetPath()
# Material/MyMaterial/Shader
shader = UsdShade.Shader.Define(stage, myMaterialPath.AppendChild('Shader'))
shader.CreateIdAttr().Set('UsdPreviewSurface')
shader.CreateInput('diffuseColor', Sdf.ValueTypeNames.Color3f).Set((0, 1, 0))
shader.CreateInput('metalic', Sdf.ValueTypeNames.Float).Set(0.9)
shader.CreateInput('roughness', Sdf.ValueTypeNames.Float).Set(0.2)
shaderOutput = shader.CreateOutput('surface', Sdf.ValueTypeNames.Token)
# Connect
myMaterialOutput.ConnectToSource(shaderOutput)
# Model
model = stage.DefinePrim('/Model')
modelPath = model.GetPath()
# Model/Sphere
sphere = UsdGeom.Sphere.Define(stage, f'{modelPath}/Sphere')
UsdShade.MaterialBindingAPI(sphere.GetPrim()).Bind(myMaterial)
layer.Export('Base.usda')
突然,難易度が上がりました。前回は DefinePrim でプリムを定義していましたが,今回は UsdGeomSphere や UsdShadeMaterial 等の「スキーマ」を使用します。アトリビュートをカスタマイズするのに,それらに実装されている CreateInput や CreateOutput を特性に応じて使用しています。また,Binding や Connect といったものも現れています。これらについては後から勉強することにしまして,本題のサブレイヤーの学習を進めていきます。
AddColor.usda(赤い玉)を出力する Python のコードです。
from pxr import Usd, Sdf, UsdShade
stage = Usd.Stage.CreateInMemory()
layer = stage.GetRootLayer()
layer.subLayerPaths = ['./Base.usda']
# Material
material = stage.OverridePrim('/Material')
materialPath = material.GetPath()
# Material/MyMaterial
myMaterial = UsdShade.Material.Define(stage, f'{materialPath}/MyMaterial')
myMaterialPath = myMaterial.GetPath()
# Material/MyMaterial/Shader
shader = UsdShade.Shader.Define(stage, myMaterialPath.AppendChild('Shader'))
shader.CreateInput('diffuseColor', Sdf.ValueTypeNames.Color3f).Set((1, 0, 0))
layer.Export('AddColor.usda')
USD を見てみましょう。メタ情報に subLayers が付与されています。そして各プリムの定義箇所には,def ではなく over が記述されていることに気がつきます。元の Python のプログラムに目を戻してみれば,レイヤのsubLayerPaths アトリビュートにサブレイヤの USD ファイル名を与えています。また,プリムの定義箇所では OverridePrim を使用しています。
#usda 1.0
(
subLayers = [
@./Base.usda@
]
)
over "Material"
{
over "MyMaterial"
{
over "Shader"
{
color3f inputs:diffuseColor = (1, 0, 0)
}
}
}
元ネタ記事の Final.usda を出力する Python のプログラムも書いてみます。今度は,Sphere プリムが UsdGeomCube によってオーバーライドされています。Final.usda を開いてみると,Sphere が Cube になっても色情報が引き継がれていることが確認できます。
from pxr import Usd, UsdGeom
stage = Usd.Stage.CreateInMemory()
layer = stage.GetRootLayer()
layer.subLayerPaths = ['./AddColor.usda']
# Model
model = stage.OverridePrim('/Model')
modelPath = model.GetPath()
sphere = UsdGeom.Cube.Define(stage, f'{modelPath}/Sphere')
layer.Export('Final.usda')
#usda 1.0
(
subLayers = [
@./AddColor.usda@
]
)
over "Model"
{
def Cube "Sphere"
{
}
}
usdcat --flatten Final.usda
#usda 1.0
(
doc = """Generated from Composed Stage of root layer /home/kagei/USD/myLearn/Reincarnation/02_sublayer/Final.usda
"""
)
def "Material"
{
def Material "MyMaterial"
{
token outputs:surface.connect = </Material/MyMaterial/Shader.outputs:surface>
def Shader "Shader"
{
uniform token info:id = "UsdPreviewSurface"
color3f inputs:diffuseColor = (1, 0, 0)
float inputs:metalic = 0.9
float inputs:roughness = 0.2
token outputs:surface
}
}
}
def "Model"
{
def Cube "Sphere"
{
rel material:binding = </Material/MyMaterial>
}
}
まとめ
今回は,コンポジションアークに関わる「サブレイヤー」を学習しました。レイヤーを重ねて引き継がれる情報とオーバーライドされる情報の成り立ちが例題でよく理解できました。シーングラフのより深い記述(Material や Shader)については今回深入りしませんでしたが,いずれ戻ってきて学習したいと思います。