Source code for axe_usd.usd.asset_files

"""Component-builder USD asset file structure."""

from dataclasses import dataclass
from pathlib import Path
from typing import Optional

from pxr import Kind, Sdf, Usd, UsdGeom

from ..core.filesystem import DefaultFileSystem
from .asset_structure import initialize_component_asset

DEFAULT_UP_AXIS = "Y"
DEFAULT_METERS_PER_UNIT = 1
DEFAULT_FRAMES_PER_SECOND = 24
DEFAULT_TIME_CODES_PER_SECOND = 24

MTL_LIBRARY_ROOT = "ASSET_mtl_default"
MTL_VARIANT_SET = "mtl"
MTL_VARIANT_DEFAULT = "default"


[docs] @dataclass(frozen=True) class AssetFilePaths: """Component-builder USD asset file paths. Structure: /AssetName/ AssetName.usd # Main entry point (payloads payload.usdc) payload.usdc # References mtl.usdc and geo.usdc geo.usdc # Geometry layer mtl.usdc # Material layer /textures/ # Texture maps (handled by DCC plugin) """ root_dir: Path # /AssetName/ asset_file: Path # /AssetName/AssetName.usd payload_file: Path # /AssetName/payload.usdc geo_file: Path # /AssetName/geo.usdc mtl_file: Path # /AssetName/mtl.usdc textures_dir: Path # /AssetName/textures/
[docs] def create_asset_file_structure( output_dir: Path, asset_name: str, ) -> AssetFilePaths: """Create component-builder file structure. Args: output_dir: Parent directory to create asset folder in. asset_name: Name of the asset (e.g., "MyProp"). Returns: AssetFilePaths: Paths to all asset files. Example: >>> paths = create_asset_file_structure(Path("./output"), "Hero") >>> # Creates: ./output/Hero/Hero.usd, payload.usdc, etc. """ fs = DefaultFileSystem() # Create asset root directory asset_root = output_dir / asset_name fs.ensure_directory(asset_root) # Create textures directory for maps (handled elsewhere) textures_dir = asset_root / "textures" fs.ensure_directory(textures_dir) return AssetFilePaths( root_dir=asset_root, asset_file=asset_root / f"{asset_name}.usd", payload_file=asset_root / "payload.usdc", geo_file=asset_root / "geo.usdc", mtl_file=asset_root / "mtl.usdc", textures_dir=textures_dir, )
[docs] def create_asset_usd_file( paths: AssetFilePaths, asset_name: str, ) -> Usd.Stage: """Create the main Asset.usd file. Creates: - /__class__/AssetName (class prim) - /AssetName (root Xform, Kind=component, assetInfo, inherits) - Payloads payload.usdc into /AssetName Args: paths: Asset file paths. asset_name: Name of the asset. Returns: Usd.Stage: The created main asset stage. """ # Create main asset file stage = Usd.Stage.CreateNew(str(paths.asset_file)) _apply_stage_metadata(stage) # Initialize component root root_prim = initialize_component_asset( stage, asset_name, asset_identifier=f"./{asset_name}.usd" ) # Payload component composition root_prim.GetPayloads().AddPayload("./payload.usdc") # Set defaultPrim stage.SetDefaultPrim(root_prim) stage.Save() return stage
[docs] def create_payload_usd_file( paths: AssetFilePaths, asset_name: str, ) -> Usd.Stage: """Create payload.usdc that references mtl.usdc and geo.usdc. Args: paths: Asset file paths. asset_name: Name of the asset. Returns: Usd.Stage: The created payload stage. """ stage = Usd.Stage.CreateNew(str(paths.payload_file)) _apply_stage_metadata(stage) # Define root prim root = stage.DefinePrim(f"/{asset_name}") Usd.ModelAPI(root).SetKind(Kind.Tokens.component) # Reference material and geometry layers (order matters) root.GetReferences().AddReference("./mtl.usdc") root.GetReferences().AddReference("./geo.usdc") # Set defaultPrim just in case stage.SetDefaultPrim(root) stage.Save() return stage
[docs] def create_geo_usd_file( paths: AssetFilePaths, asset_name: str, ) -> Usd.Stage: """Create geo.usdc geometry layer scaffold. Args: paths: Asset file paths. asset_name: Name of the asset. Returns: Usd.Stage: The created geometry stage. """ if paths.geo_file.exists(): stage = Usd.Stage.Open(str(paths.geo_file)) else: stage = Usd.Stage.CreateNew(str(paths.geo_file)) _apply_stage_metadata(stage) root_path = Sdf.Path(f"/{asset_name}") root_prim = stage.GetPrimAtPath(root_path) if not root_prim.IsValid(): root_prim = UsdGeom.Xform.Define(stage, root_path).GetPrim() geo_scope = _ensure_scope(stage, f"/{asset_name}/geo") if geo_scope: UsdGeom.ModelAPI.Apply(geo_scope.GetPrim()) proxy_scope = _ensure_scope(stage, f"/{asset_name}/geo/proxy") if proxy_scope: UsdGeom.Imageable(proxy_scope.GetPrim()).CreatePurposeAttr().Set("proxy") render_scope = _ensure_scope(stage, f"/{asset_name}/geo/render") if render_scope: UsdGeom.Imageable(render_scope.GetPrim()).CreatePurposeAttr().Set("render") render_scope.GetPrim().CreateRelationship("proxyPrim").SetTargets( [Sdf.Path(f"/{asset_name}/geo/proxy")] ) stage.SetDefaultPrim(root_prim) stage.Save() return stage
[docs] def create_mtl_usd_file( paths: AssetFilePaths, asset_name: str, ) -> Usd.Stage: """Create mtl.usdc for the material layer. Args: paths: Asset file paths. asset_name: Name of the asset. Returns: Usd.Stage: The created material stage. """ stage = Usd.Stage.CreateNew(str(paths.mtl_file)) _apply_stage_metadata(stage) root_prim = UsdGeom.Xform.Define(stage, f"/{asset_name}").GetPrim() root_prim.GetReferences().AddInternalReference(f"/{MTL_LIBRARY_ROOT}") _ensure_variant_set(root_prim, MTL_VARIANT_SET, MTL_VARIANT_DEFAULT) UsdGeom.Scope.Define(stage, f"/{MTL_LIBRARY_ROOT}") UsdGeom.Scope.Define(stage, f"/{MTL_LIBRARY_ROOT}/mtl") stage.SetDefaultPrim(root_prim) stage.Save() return stage
def _apply_stage_metadata(stage: Usd.Stage) -> None: stage.SetMetadata("upAxis", DEFAULT_UP_AXIS) stage.SetMetadata("metersPerUnit", DEFAULT_METERS_PER_UNIT) stage.SetMetadata("framesPerSecond", DEFAULT_FRAMES_PER_SECOND) stage.SetMetadata("timeCodesPerSecond", DEFAULT_TIME_CODES_PER_SECOND) def _ensure_scope(stage: Usd.Stage, path: str) -> Optional[UsdGeom.Scope]: prim = stage.GetPrimAtPath(path) if prim and prim.IsValid(): if prim.IsA(UsdGeom.Scope): return UsdGeom.Scope(prim) return None return UsdGeom.Scope.Define(stage, path) def _ensure_variant_set( prim: Usd.Prim, set_name: str, variant_name: str ) -> Usd.VariantSet: variant_sets = prim.GetVariantSets() variant_set = variant_sets.AddVariantSet(set_name) if variant_name not in variant_set.GetVariantNames(): variant_set.AddVariant(variant_name) variant_set.SetVariantSelection(variant_name) return variant_set