USD Composer 2023.1.1 BetaでC++やPythonでUSDを操作するにあたっていくつか修正が必要でしたので、それらについて列挙します。
USD 20.08から22.11に大きくバージョンアップされましたので、それの仕様変更になります。
また、USD Composerの"Asset Validator"もUSDの構文チェックで非常に使えました。
Asset Validatorを使って検証した内容も押さえるポイントとして追加します。
大きくUSD自身の仕様変更とOmniverseの開発における仕様変更がありますが、今回は前者についての解説になります。
なお、コードについてはPythonの場合で説明します。
from pxr import Usd, UsdGeom, UsdPhysics, UsdShade, Sdf, Gf, Tf
# Get stage.
stage = omni.usd.get_context().get_stage()
のように現在のステージを取得しているものとします。
なお、GitHub上でのUSDのリリース日は以下のようになっていました。
USDのバージョン | Release日 |
---|---|
USD 20.08 | Jul 21, 2020 |
USD 22.11 | Oct 22, 2022 |
Omniverse(Omniverse Create → USD Composer)では、July, 2023にUSD 20.08から22.11に移行されました。
USDのヘッダ情報の明確化 (Asset Validatorで検出)
ヘッダ情報をデフォルトでも明示指定する必要があります。
パラメータ名 | デフォルト | 内容 |
---|---|---|
metersPerUnit | 0.01 | ステージの距離の単位。1.0でm、0.01でcm |
upAxis | Y | ステージのアップベクトル。’Y’または’Z’ |
Pythonでは以下のように指定します。
UsdGeom.SetStageMetersPerUnit(stage, 0.01)
UsdGeom.SetStageUpAxis(stage, UsdGeom.Tokens.y)
Primvarsの取得方法の変更
Meshの場合はUVや独自パラメータはprimvarに指定します。
USD 20.08は以下のように記述していました。
m = UsdGeom.Mesh(prim)
primvars = m.GetPrimvars()
これが廃止になり、USD 22.11では以下のようになります。
primvarsAPI = UsdGeom.PrimvarsAPI(prim)
primvars = primvarsAPI.GetPrimvars()
MaterialへのShaderの割り当て方法の変更
OmniPBRを作成しこれにShaderを割り当てる場合に、USD 20.08では以下のように記述していました。
materialPrimPath = "/World/Looks/OmniPBR_mat"
diffuseColor = Gf.Vec3d(1, 0, 0.2)
material = UsdShade.Material.Define(stage, materialPrimPath)
shaderPath = materialPrimPath + "/Shader"
shader = UsdShade.Shader.Define(stage, shaderPath)
shader.SetSourceAsset("OmniPBR.mdl", "mdl")
shader.GetPrim().CreateAttribute("info:mdl:sourceAsset:subIdentifier", Sdf.ValueTypeNames.Token, False, Sdf.VariabilityUniform).Set("OmniPBR")
# Set Diffuse color.
shader.CreateInput("diffuse_color_constant", Sdf.ValueTypeNames.Color3f).Set(diffuseColor)
# Connecting Material to Shader.
mdlOutput = material.CreateSurfaceOutput("mdl")
mdlOutput.ConnectToSource(shader, "out") # Error!
最終行の"mdlOutput.ConnectToSource(shader, "out")"は使えなくなりました。
mdlOutput.ConnectToSource(shader, "out")
shaderは"shader.ConnectableAPI()"に変更する必要があります。
mdlOutput.ConnectToSource(shader.ConnectableAPI(), "out")
Schemaの明確化 (Asset Validatorで検出)
これはPythonでのプログラミングでは関係なく、usdファイルでの指定の件になります。
形状にマテリアルをバインドする際にusdaでは以下のように出力されました。
※ これはエラーにはなりませんが、正しくない出力です。
def Sphere "sphere" (
)
{
float3[] extent = [(-20, -20, -20), (20, 20, 20)]
rel material:binding = </World/Looks/omniPBR_mat1>
double radius = 20
}
マテリアルのバインド時はPythonでは以下のように記述します。
# Create sphere
spherePath = "/World/sphere"
sphereGeom = UsdGeom.Sphere.Define(stage, spherePath)
prim = sphereGeom.GetPrim()
sphereGeom.CreateRadiusAttr(20.0)
# Create material
materialPath = "/World/Looks/omniPBR_mat1"
material = UsdShade.Material.Define(stage, materialPath)
# Bind material
bindAPI = UsdShade.MaterialBindingAPI(prim)
bindAPI.Bind(material)
bindAPI.Apply(prim) # This is important!
MaterialBindingAPIを使用しています。
ここで生成したusdをusdaでエクスポートすると以下のようになりました。
def Sphere "sphere" (
apiSchemas = ["MaterialBindingAPI"]
)
{
float3[] extent = [(-20, -20, -20), (20, 20, 20)]
rel material:binding = </World/Looks/omniPBR_mat1>
double radius = 20
}
"apiSchemas = ["MaterialBindingAPI"]"が追加されました。
xxxAPIを使う際は、Applyで確定するようにしたほうがよさそうです。
これにより、どのスキーマを使用したかが明示化されるようです。
なお、UsdGeom.PrimvarsAPIではこのApplyはありませんでした。
Lightの作成 (Asset Validatorで検出)
PythonやC++の開発側ではUSD SDKが自動で対処してくれるため意識する必要はありません。
usdaでは、過去のLightは以下のような出力になっていました。
def DistantLight "distantLight"
{
color3f color = (1, 0.5, 0.2)
float exposure = 0
float intensity = 100
}
Pythonで以下を実行します。
# Create distant light.
pathName = "/World/distantLight"
light = UsdLux.DistantLight.Define(stage, pathName)
# Set intensity.
light.CreateIntensityAttr(100.0)
# Set color.
light.CreateColorAttr(Gf.Vec3f(1.0, 0.5, 0.2))
# Set Exposure.
light.CreateExposureAttr(0.0)
USD Composer 2023.1.1では、usdaファイルは以下のようになりました。
def DistantLight "distantLight"
{
color3f inputs:color = (1, 0.5, 0.2)
float inputs:exposure = 0
float inputs:intensity = 100
}
すべてのLightのパラメータで"inputs:"が追加されました。
また、ライトの角度を割り当てる場合は"Shaping"を使います。
この場合はUsdLux.ShapingAPIを使用するため、Applyを忘れずに行うようにします。
Pythonで以下を実行します。
# Create sphere light.
pathName = "/World/sphereLight"
light = UsdLux.SphereLight.Define(stage, pathName)
# Set Radius.
light.CreateRadiusAttr(2.0)
# Set intensity.
light.CreateIntensityAttr(10000.0)
# Set color.
light.CreateColorAttr(Gf.Vec3f(1.0, 0.9, 0.8))
# Set Exposure.
light.CreateExposureAttr(0.0)
# cone angle.
shapingAPI = UsdLux.ShapingAPI(light)
shapingAPI.CreateShapingConeAngleAttr(180.0)
shapingAPI.Apply(light.GetPrim()) # This is important!
usdaでは以下のように出力されました。
def SphereLight "sphereLight" (
apiSchemas = ["ShapingAPI"]
)
{
color3f inputs:color = (1, 0.9, 0.8)
float inputs:exposure = 0
float inputs:intensity = 10000
float inputs:radius = 2
float inputs:shaping:cone:angle = 180
}
"shaping:cone:angle"の前に"inputs:"がついているのを確認できます。
extentの明示指定 (Asset Validatorで検出)
Primの形状を囲むローカルのバウンディングボックスは"extent"で指定できます。
これは省略しても動作に問題なさそうでしたが、
Why Extent and not Bounds ?
https://openusd.org/release/api/class_usd_geom_boundable.html#details
内部で使われているようなので念のためextentは明示します。
Asset Validatorを使った場合、extent未使用のときは警告されました。
このextentが使用できるのはSphereやMeshなどのジオメトリやライト(DistantLightやDomeLightは除く)があります。
SphereやCubeなどのジオメトリは、extentは自動で割り当てられます。
MeshやLightは、以下のようにextentを計算して割り当てることができます。
# Create mesh.
meshGeom = UsdGeom.Mesh.Define(stage, "/World/mesh")
# Assign various parameters.
...
# Compute extent.
boundable = UsdGeom.Boundable(meshGeom.GetPrim())
extent = boundable.ComputeExtent(Usd.TimeCode(0))
# Set Extent.
meshGeom.CreateExtentAttr(extent)
"UsdGeom.Boundable"でextent計算用のクラスを作成し、ComputeExtentで計算。
その結果をジオメトリの"CreateExtentAttr"でセットします。
新たに発見次第、これらのUSDのバージョンにより変更が必要な点はブログで追記していく予定です。