LearnOpenUSD · repaso condensado
Guía de estudio: de Stage Setting a Beyond Basics
Notas de repaso para los cuatro primeros módulos del learning path de Learn OpenUSD: cómo se construye un Stage, cómo se describen prims y schemas, cómo se compone escena entre capas, y las técnicas de producción que vienen después de lo básico. Cada tema resume conceptos, código representativo y trampas típicas de examen, con preguntas de autoevaluación al final.
4Módulos
29Temas
~95Preguntas de repaso
La base de todo lo demás: qué es un Stage, de qué están hechos los prims, cómo se los localiza con paths, qué tipos de propiedades existen, y en qué formato y unidad de tiempo vive todo esto en disco.
El Stage Usd.Stage
El Stage es el scenegraph ya compuesto: el resultado de ensamblar uno o más layers, no un archivo en sí mismo. Es la vista unificada que USD te entrega para leer o autorar la jerarquía de prims.
- Composición es el algoritmo que ensambla layers en un stage; el root layer es el primer layer abierto y el ancla de la layer stack.
- Ventajas de trabajar sobre un stage: edición no destructiva (modularidad) y escalabilidad de datos grandes vía payloads.
- Los sublayers de un mismo stage pueden mezclar formatos (
.usda + .usdc conviviendo).
Crear, abrir y guardar un stage
from pxr import Usd
stage = Usd.Stage.CreateNew("scene.usda") # nuevo stage respaldado en disco
stage = Usd.Stage.Open("scene.usda") # abre un stage existente
stage = Usd.Stage.CreateInMemory() # solo en memoria, no toca disco
stage.GetRootLayer() # Sdf.Layer ancla de la layer stack
stage.Save() # guarda todos los layers editados
stage.GetRootLayer().subLayerPaths.append("./lighting.usda")
OjoCreateInMemory() no escribe nada a disco hasta que llamás explícitamente a Export(). Y Save() escribe en el root layer salvo que haya otros layers editados involucrados.
Autoevaluación
¿Un Stage es un archivo?
No. Es el scenegraph compuesto resultante de ensamblar layers en tiempo de apertura; el archivo es el layer.
¿Qué método crea un stage sin escribir nada a disco?
Usd.Stage.CreateInMemory().
¿Qué habilita la escalabilidad de datos grandes en un stage?
Los payloads, que permiten cargar/descargar subgrafos pesados en runtime.
Prims Usd.Prim
El prim es el bloque de construcción central: un contenedor que agrupa attributes y relationships, y que puede estar tipado (Sphere, Xform, Cube…) o quedar typeless como contenedor vacío.
DefinePrim(path) sin tipo produce un prim typeless; para un tipo con API dedicada se usa el schema (p. ej. UsdGeom.Xform.Define).
GetChild("Name") solo busca hijos directos, nunca nietos; si no existe devuelve un prim inválido.
Definir e inspeccionar prims
from pxr import UsdGeom
stage.DefinePrim("/World/Empty") # prim typeless
UsdGeom.Xform.Define(stage, "/World/Xf") # prim tipado vía schema API
prim = stage.GetPrimAtPath("/World/Xf")
prim.GetTypeName()
prim.GetChildren()
prim.GetProperties()
child = prim.GetChild("NoExiste")
bool(child) # False si el prim es inválido
OjoUn prim inválido evalúa a False como booleano — es el patrón estándar para chequear existencia sin lanzar excepciones.
Autoevaluación
¿Qué devuelve DefinePrim("/x") sin segundo argumento?
Un prim sin tipo (typeless), un contenedor vacío.
Diferencia entre Xform y Scope como tipos de prim
Xform almacena datos de transformación; Scope es puramente organizativo y no es transformable.
¿GetChild("Box") encuentra un nieto llamado Box?
No, solo busca entre los hijos directos del prim.
Prim & property paths Sdf.Path
Un path ubica de forma única un prim o una propiedad en el scenegraph. La raíz del stage es el pseudo-root /.
- Prim path: segmentos separados por
/ (/geo/box). Property path: un . tras el prim path (/geo/box.weight). Variant: llaves (/geo/box{size=large}).
- Usos típicos: identificar de forma única, navegar la jerarquía, especificar dónde autorar, y filtrar/query con
Sdf.PathExpression.
Construir y validar paths
from pxr import Sdf
path = Sdf.Path("/World").AppendChild("Geometry")
path.IsPrimPath()
path.GetParentPath()
prim = stage.GetPrimAtPath("/World/NoExiste")
prim.IsValid() # SIEMPRE validar tras GetPrimAtPath
prop_path = sphere.GetPath().AppendProperty("userProperties:tag")
owner_prim.CreateAttribute("userProperties:tag", Sdf.ValueTypeNames.String)
OjoConstruir un property path con AppendProperty no crea la propiedad. Solo describe una ubicación; hace falta CreateAttribute/CreateRelationship sobre el prim dueño para que exista de verdad.
Autoevaluación
¿Qué símbolo separa una propiedad de su prim en un path?
El punto (.): /geo/box.weight.
¿Qué representa /geo/box{size=large}?
Una selección de variant en el prim /geo/box.
¿Qué hay que comprobar siempre después de GetPrimAtPath?
IsValid() — el path puede no resolver a ningún prim.
Attributes UsdAttribute
Un attribute es un par nombre–valor con un único tipo de dato (definido vía Sdf), que puede tener un valor por defecto y/o time samples para animación.
- Se prefiere la API específica del schema (
GetRadiusAttr()) sobre manipular UsdAttribute genéricos a mano: es más clara y menos frágil ante cambios.
- Si nunca se autoró un valor,
Get() devuelve el fallback del schema — ese valor no aparece escrito en el .usda.
Leer y escribir un attribute
sphere.GetRadiusAttr().Get() # aplica value resolution
sphere.GetRadiusAttr().Set(100.0) # autora un valor
cube.GetPrim().GetPropertyNames()
cube.GetPrim().GetAttributes()
OjoEjemplos comunes de attributes: visibility, displayColor, extent. Ninguno de estos "existe" en el archivo si nadie lo autoró — resuelven al fallback del schema.
Autoevaluación
¿Qué devuelve Get() sobre un attribute nunca seteado?
El valor fallback definido por el schema, vía value resolution.
¿Qué API es preferible para un attribute conocido de un schema?
La API específica (p. ej. GetRadiusAttr()), no UsdAttribute genérica.
¿Puede un attribute cambiar de tipo de dato entre capas?
No, cada attribute tiene un único tipo fijado.
Relationships UsdRelationship
Una relationship es una propiedad sin tipo de dato: almacena uno o más target paths que apuntan a otros prims, attributes u otras relationships, y se remapea automáticamente si el target cambia de ubicación.
- No es lo mismo que una attribute connection (que conecta dos attributes existentes entre sí); una relationship apunta desde cero a otros objetos.
- Ejemplo built-in:
proxyPrim en UsdGeom.Imageable, que apunta un prim costoso a un proxy liviano para vista previa.
Crear y usar una relationship
from pxr import UsdShade
group.CreateRelationship("members", custom=True).SetTargets(
[sphere.GetPath(), cube.GetPath()]
)
rel.GetTargets()
rel.AddTarget(path)
# material:binding es una relationship gestionada por una API schema
UsdShade.MaterialBindingAPI.Apply(prim).Bind(material)
OjoLa ventaja frente a un path "hardcodeado" a mano: si el target se mueve o se renombra, la relationship sigue apuntando correctamente (path translation automática).
Autoevaluación
¿Tiene una relationship un tipo de dato como un attribute?
No; su "tipo" es simplemente un enlace a otros objetos.
¿Qué ventaja da sobre un path hardcodeado?
Se remapea sola si el target cambia de ubicación (path translation).
¿Puede una relationship tener más de un target?
Sí, puede apuntar a múltiples targets a la vez.
Metadata
Pares nombre–valor no animables, adjuntos a prims, properties o layers, que viven fuera del modelo de datos del schema y se acceden como un diccionario.
- Metadata vs. attribute: metadata es info suplementaria fuera del schema y nunca tiene time samples; attribute es dato core del objeto y sí puede animarse.
- Las keys más comunes son
assetInfo y customData; se pueden agregar keys nuevas vía schemas adicionales.
Leer y escribir metadata
prim.GetMetadata("customData")
prim.SetMetadata("customData", {"reviewed": True})
stage.SetMetadata("comment", "revisión interna")
prim.GetMetadataByDictKey("customData", "reviewed") # más eficiente para 1 valor
Autoevaluación
¿Puede la metadata tener time samples?
No, nunca es animable.
¿Cuáles son las dos keys de metadata más comunes?
assetInfo y customData.
Diferencia esencial metadata vs. attribute
Metadata queda fuera del schema (solo info suplementaria); attribute es parte del schema y del dato del objeto.
Time codes & time samples
Un time code es un punto en el tiempo sin unidad intrínseca (como un frame), escalado por timeCodesPerSecond. Un time sample es el valor de un attribute en un time code puntual; entre samples se interpola linealmente.
- Con
timeCodesPerSecond = 24, el time code 48.0 equivale a 2 segundos reales (48/24).
- Los time samples son animación "horneada" por frame — buenos para intercambio reproducible, no para reemplazar curvas de animación complejas (eso se hace en la DCC).
Autorar valores en el tiempo
stage.SetStartTimeCode(1)
stage.SetEndTimeCode(60)
cube.GetDisplayColorAttr().GetTimeSamples()
attr.Set(value, time=30)
xform_api.SetTranslate((0, -4.5, 0), time=30)
Autoevaluación
¿Un time code tiene unidad intrínseca?
No; es unitless, se escala vía timeCodesPerSecond.
Con 24 tcps, ¿a qué segundo real corresponde el time code 48?
2 segundos (48 / 24).
¿Qué pasa al evaluar un tiempo entre dos samples consecutivos?
Se interpola linealmente entre ambos valores.
Formatos de archivo
USD define cuatro formatos nativos, cada uno pensado para un rol distinto en el pipeline.
- .usda — ASCII, legible por humanos; ideal para capas pequeñas de interfaz/agregación y para debugging o diffing.
- .usdc (Crate binary) — binario comprimido y memory-mapped; carga rápido y usa poca memoria, ideal para geometría pesada.
- .usd — puede ser ASCII o binario por dentro; se puede cambiar el formato interno sin romper referencias.
- .usdz — paquete zip atómico sin comprimir, pensado como read-only para distribución (p. ej. XR); no se usa mientras se sigue editando el asset.
Regla prácticaPreferir binario (.usdc/.usd) para capas de datos pesados (geometría, shading) y texto (.usda) para capas ligeras de interfaz y debugging.
Autoevaluación
¿Qué formato conviene para geometría pesada en producción?
USDC (crate binary): carga más rápido y usa menos memoria.
¿Por qué no usar .usdz mientras se edita un asset?
Es un paquete atómico pensado como read-only para distribución final, no para edición iterativa.
¿Puede un archivo .usd ser texto o binario?
Sí, cualquiera de los dos, sin romper referencias existentes.
Módulos de USD pxr
Para autoría y lectura básica alcanza con los paquetes base y usd; los módulos imaging/usdImaging entran en juego al renderizar.
- Usd — módulo cliente central: Stage, Prims, Properties, Metadata, arcos de composición.
- Sdf (Scene Description Foundation) — serialización a texto,
SdfLayer, manejo de paths, creación de layers.
- Gf (Graphics Foundation) — álgebra lineal y tipos básicos (
Gf.Vec3d, matrices) usados al leer/escribir attributes.
- Módulos de schema por dominio:
UsdGeom, UsdShade, UsdPhysics, UsdLux…
from pxr import Usd, Sdf, Gf, UsdGeom
Autoevaluación
¿Qué módulo maneja Sdf.Path y la creación de layers?
Sdf.
¿Qué módulo provee tipos como Gf.Vec3d?
Gf.
¿Qué dos paquetes bastan para autoría/lectura básica?
base y usd.
Un prim sin schema es un contenedor vacío. Este módulo cubre los schemas que le dan significado real: qué lo tipa (IsA), qué comportamiento adicional le suma (API), y los bloques concretos más comunes — organización, transformación, luces y materiales.
Schemas: IsA vs. API
Un schema es un blueprint que le da significado y capacidades a un prim. No necesariamente implementa comportamiento (p. ej. UsdPhysics no trae un motor de física): define el modelo de datos y las reglas de interpretación.
- IsA schemas dicen qué es el prim, vía metadata
typeName. Un prim solo puede tener una. Pueden ser concretas (instanciables: UsdGeomMesh) o abstractas (solo sirven de base: UsdGeomPointBased).
- API schemas dicen qué puede hacer además: no tienen
typeName, se listan en la metadata apiSchemas y se consultan con HasAPI. Pueden ser applied/non-applied y single/multiple-apply.
- Convención de nombre: sufijo "API"; propiedades namespaced en camelCase (
RigidBodyAPI.CreateVelocityAttr() → atributo physics:velocity).
IsA vs. API en código
from pxr import UsdGeom, UsdPhysics
# IsA schema: define qué es el prim (typeName = Sphere)
sphere = UsdGeom.Sphere.Define(stage, "/World/Sphere")
sphere.GetRadiusAttr().Set(10)
# API schema: suma comportamiento a un prim ya tipado
rb_api = UsdPhysics.RigidBodyAPI.Apply(cube.GetPrim())
rb_api.CreateVelocityAttr(5)
cube.GetPrim().HasAPI(UsdPhysics.RigidBodyAPI)
OjoUna luz típica mezcla ambas: UsdLuxDiskLight aporta atributos propios (radius) vía su IsA schema, más intensity vía la API schema LightAPI.
Autoevaluación
¿Cuántas IsA schemas puede tener un prim a la vez?
Solo una.
¿Cómo se detecta si un prim tiene una API schema aplicada?
Con HasAPI(...).
¿Qué diferencia una schema concreta de una abstracta?
La concreta tiene typeName y es instanciable; la abstracta solo aporta un name base, sin ser instanciable por sí sola.
¿Qué significa que una API schema sea "multiple-apply"?
Que puede aplicarse varias veces al mismo prim, cada vez con un nombre de instancia distinto.
Scope UsdGeom.Scope
Un contenedor puro de agrupación, análogo a una carpeta vacía: no es transformable ni representa geometría renderizable por sí mismo.
- Se usa para organizar materiales, geometría, animación o grupos de actores/entorno dentro de la jerarquía.
- Los hijos transformables dentro de un Scope se evalúan con normalidad, aunque el Scope mismo no aporte transform.
from pxr import UsdGeom
a_scope = UsdGeom.Scope.Define(stage, "/World/A_Scope")
prim.IsA(UsdGeom.Scope)
a_scope.GetPrim().SetActive(False) # desactiva el scope y TODO su contenido
OjoDesactivar el Scope raíz de un grupo apaga de un solo golpe todo su contenido — útil para encender/apagar actores o entornos completos.
Autoevaluación
¿Puede un Scope tener transformaciones propias?
No, es un contenedor puro no transformable.
¿Qué pasa con los hijos de un Scope desactivado?
Se desactivan junto con él.
Xform UsdGeom.Xform
Un prim que almacena datos de transformación — traslación, rotación, escala — que afectan a todos sus hijos en la jerarquía. "Xform" es literalmente "transform".
UsdGeomImageable es la base de todo lo visualizable; UsdGeomXformable encapsula el schema de lo transformable; UsdGeomXform es el schema concreto de un transform puro.
- Toda la geometría de
UsdGeom es directamente transformable, porque hereda de Xformable.
xf = UsdGeom.Xform.Define(stage, "/World/Xf")
xf.GetXformOpOrderAttr() # orden de las operaciones de transform
xf.AddXformOp(UsdGeom.XformOp.TypeTranslate)
OjoEl orden de las xformOps importa: aplicar rotación antes o después de escala da resultados distintos. Por eso conviene XformCommonAPI cuando no se necesita control fino.
Autoevaluación
¿Qué clase base agrupa todo lo "visualizable" en UsdGeom?
UsdGeomImageable.
¿Por qué importa el orden de las xformOps?
Distintos órdenes de aplicación producen distintos resultados de transformación combinada.
XformCommonAPI
Una API schema no aplicada que estandariza un set común de operaciones — translate, rotate, scale y pivote — compatible entre herramientas de import/export.
- Fija el orden y el set de operaciones permitidas: se pierde la flexibilidad total de
AddXformOp, se gana interoperabilidad y queries simples ("¿posición en el frame 101?").
- Compatibilidad se verifica evaluando el objeto como booleano.
xform_api = UsdGeom.XformCommonAPI(prim)
if not xform_api:
raise ValueError("prim no compatible con XformCommonAPI")
xform_api.SetTranslate((10.0, 20.0, 30.0))
xform_api.SetRotate((45.0, 0.0, 90.0), UsdGeom.XformCommonAPI.RotationOrderXYZ)
xform_api.SetScale((2.0, 2.0, 2.0))
OjoAunque scale/rotate/translate/pivot son técnicamente attributes editables a mano, siempre conviene tocarlos vía XformCommonAPI en vez de manipular las xformOps directamente.
Autoevaluación
¿Es XformCommonAPI una IsA schema o una API schema?
Una API schema no aplicada.
¿Qué se gana y qué se pierde frente a xformOps arbitrarios?
Se gana interoperabilidad y queries simples; se pierde flexibilidad de orden y set de operaciones.
Lights UsdLux
UsdLux agrupa los schemas de iluminación: DistantLight (direccional), luces de área (Cylinder, Rect, Disk, Sphere), DomeLight y PortalLight. Todas son Xformable.
- Combinan atributos propios (color, vía su IsA schema) con atributos comunes de
LightAPI (intensity).
DistantLight emite a lo largo del eje -Z local del prim; por eso su dirección se controla rotando el prim, no moviéndolo.
from pxr import UsdLux, Gf
light = UsdLux.DistantLight.Define(stage, "/World/Sun")
light.GetColorAttr().Set(Gf.Vec3f(1.0, 0.95, 0.9))
light.GetIntensityAttr().Set(120.0)
UsdGeom.XformCommonAPI(light).SetRotate((45.0, 0.0, 0.0))
Autoevaluación
¿En qué eje emite una DistantLight por defecto?
-Z local del prim.
¿Las luces son transformables?
Sí, son Xformable como cualquier geometría.
Nombra los 4 tipos de luz de área en UsdLux
Cylinder, Rect, Disk y Sphere light.
Materials & shaders UsdShade
UsdShade es el schema para crear materiales y hacerles bind a geometría. UsdShadeMaterial es el contenedor que guarda los datos de shading para un renderer.
- Definir un material no es lo mismo que aplicarlo: sin bind, el material existe en la jerarquía pero no afecta el render.
- El tratamiento completo de shaders/networks queda para módulos posteriores; aquí es solo otro ejemplo de "API específica de schema".
mat_scope = UsdGeom.Scope.Define(stage, box.GetPath().AppendPath("Materials"))
box_mat = UsdShade.Material.Define(stage, mat_scope.GetPath().AppendPath("BoxMat"))
# todavía sin bind: existe en la jerarquía, no se ve en el render
OjoNo confundir "definir un Material" con "bind-earlo" a un prim geométrico — son dos pasos distintos.
Autoevaluación
¿Qué clase de UsdShade contiene los datos de un material?
UsdShadeMaterial.
¿Por qué un material definido pero no bind-eado no cambia el render?
Porque bind y definición son pasos independientes; sin bind, el material solo existe en la jerarquía.
Lo que convierte a USD en una plataforma colaborativa y no en un simple formato de archivo: cómo se combinan layers, qué prim es el punto de entrada, qué intención declara cada prim spec, cómo se ensamblan escenas a partir de referencias y variantes, y con qué regla exacta se resuelven los conflictos.
Layers Sdf.Layer
Un layer es un archivo o recurso único que contiene un subconjunto de datos de escena (geometría, materiales, animación…). Un Stage se compone combinando layer stacks en runtime.
- Puede ser
.usd(a/c), un formato con plugin (.gltf, .fbx) o incluso no basarse en archivo (una base de datos).
layer.Reload() # descarta opiniones no guardadas de esa capa
layer.Save() # guarda el contenido de esa capa a disco
OjoNo pensar los layers como capas de Photoshop — esa analogía solo cubre sublayering, uno de varios arcos de composición. USD combina vía LIVRPS, no simplemente "gana el de arriba".
Autoevaluación
¿Qué es un layer en USD?
Un archivo o recurso único con un subconjunto de datos de escena.
¿Por qué se evita comparar layers con capas de Photoshop?
Porque esa analogía solo cubre sublayers e ignora el resto de arcos de composición (references, variants, etc.).
Default prim
El prim de nivel superior guardado como metadata de layer: el punto de entrada de un stage cuando se lo referencia sin especificar un prim path explícito.
- Vive como metadata del layer, no del prim.
usdchecker marca error si falta; si se referencia un layer sin default prim, resuelve vacío + warning.
from pxr import Usd, UsdGeom, Sdf
stage = Usd.Stage.CreateInMemory()
root = UsdGeom.Xform.Define(stage, "/World").GetPrim()
stage.SetDefaultPrim(root)
assert stage.GetDefaultPrim() == root
Autoevaluación
¿Qué método fija el default prim?
stage.SetDefaultPrim(prim).
¿Qué pasa si referenciás un .usda sin defaultPrim?
Resuelve vacío, con un warning en el log.
¿El defaultPrim es metadata del prim o del layer?
Del layer.
Specifiers def / over / class
El specifier declara la intención de un prim spec: def (concreto, visitado por traversals por defecto), over (override de opiniones existentes, edición no destructiva, no crea el prim original) y class (abstracto/blueprint, target típico de reference/inherit/specialize).
class se compone en el stage pero no es visitado por traversals por defecto.
over es el specifier más débil: resuelve a def o class según lo que exista en otras capas.
prim.GetSpecifier() # Sdf.SpecifierDef / SpecifierOver / SpecifierClass
prim.GetPrimStack() # SdfPrimSpecs, de más fuerte a más débil
stage.CreateClassPrim("/_box")
-- usda --
def Cube "Box" { double size = 4 }
over "Box" { double size = 10 }
class "_box" { double size = 4 }
OjoUn prim siempre tiene un specifier resuelto; solo un def no abstracto aparece en el traversal de render por defecto.
Autoevaluación
¿Qué specifier no es visitado por traversals de render por defecto?
class (abstracto).
¿Qué specifier habilita edición no destructiva de propiedades ya existentes?
over.
¿Qué método devuelve el prim stack de fuerte a débil?
GetPrimStack().
References
El arco de composición ("R" de LIVRPS) que compone un prim y sus descendientes sobre otro prim — la forma principal de ensamblar escenas grandes a partir de unidades modulares.
- Un arco de reference incluye identificador de layer (omitible si es interna) + prim path (omitible si el layer externo tiene default prim).
- Orden de composición: primero se compone el layer stack del prim referenciado, luego se agrega ese resultado al prim destino, y por último se aplican overrides adicionales sobre el destino.
ref_prim = stage.DefinePrim("/World/Box")
ref_prim.GetReferences().AddReference("./cube.usda") # usa el default prim de cube.usda
ref_prim.GetReferences().ClearReferences()
-- usda --
def Xform "Box" ( prepend references = @./cubebox_a02/cubebox_a02.usd@ ) {}
OjoSi se omite el prim path al referenciar un archivo externo, USD usa el default prim de ese archivo — de ahí la importancia de definirlo siempre.
Autoevaluación
¿Qué letra de LIVRPS representan las references?
La R.
¿Qué API se usa para añadir una reference?
prim.GetReferences().AddReference(assetPath[, primPath]).
Diferencia entre reference interna y externa
La interna injerta datos de otra parte de la misma jerarquía; la externa viene de otro archivo.
Variant sets
Un conjunto nombrado de representaciones alternativas para un prim, intercambiables sin duplicar datos — útil para variantes de forma, de look/material o de LOD.
- La selección de variante puede autorearse en la misma capa que define el set, o en otra capa distinta que referencia el prim — cada referencia puede elegir una opción distinta.
- Las opiniones "dentro de una variante" solo se autoran usando el
VariantEditContext.
vsets = prim.GetVariantSets()
vset = vsets.AddVariantSet("look")
vset.AddVariant("Painted")
vset.SetVariantSelection("Painted")
with vset.GetVariantEditContext():
# las opiniones autoreadas aquí solo aplican si "Painted" está activa
prim.GetAttribute("displayColor").Set([(0.8, 0.1, 0.1)])
Autoevaluación
¿Qué método crea un variant set en un prim?
prim.GetVariantSets().AddVariantSet("name").
¿Cómo se autoran opiniones que solo aplican a una variante específica?
Con vset.GetVariantEditContext() como context manager.
¿Puede cada referencia a un prim elegir una variante distinta?
Sí, la selección se puede autorear de forma independiente en cada capa que referencia.
Strength ordering: LIVRPS
El orden exacto, de más fuerte a más débil, en que USD resuelve opiniones en conflicto entre arcos de composición.
- Local — opiniones autoreadas directamente en una capa/sublayer.
- Inherits — propaga opiniones de un prim fuente a todo lo que le hace inherit (p. ej. cambiar todos los pinos de un bosque desde un único prim fuente).
- Variant sets — elige entre jerarquías alternativas.
- References — compone contenido de otra capa como subgrafo.
- Payloads — como reference, pero cargable/descargable en runtime.
- Specializes — autora un fallback: gana solo si nada más define un valor (típico en librerías de materiales).
OjoLIVRPS se aplica recursivamente: al componer una reference, dentro de ella se vuelve a aplicar Local > Inherits > Variant sets… El stage final es el resultado acumulado de aplicar esto en todos los niveles.
Autoevaluación
Ordená LIVRPS de más fuerte a más débil
Local, Inherits, Variant sets, References, Payloads, Specializes.
¿Qué arco es un "fallback" que gana solo si nada más define el valor?
Specializes.
¿Se aplica LIVRPS una sola vez a nivel de stage, o recursivamente?
Recursivamente, dentro de cada arco compuesto.
Técnicas de nivel producción una vez que el modelo básico ya se entiende: apagar contenido sin borrarlo, clasificar la jerarquía de assets, extender el modelo de datos, datos de shading por vértice, unidades consistentes entre escenas, cómo se resuelve realmente un valor, cómo recorrer el grafo de forma eficiente, y cómo llega todo esto a la pantalla.
Active / inactive prims
Todos los prims son active por defecto. Desactivar un prim es un borrado no destructivo (pruning) del stage compuesto: el prim sigue existiendo en la scene description.
- Desactivar excluye al prim (y a todos sus descendientes) de los traversals por defecto y de la composición visible.
- Es reversible por composición: una opinión más fuerte en otra capa puede reactivar un subárbol desactivado.
stage.GetPrimAtPath("/World/Parent").SetActive(False)
prim.IsActive()
Autoevaluación
¿Es destructivo desactivar un prim?
No, es pruning reversible; el prim sigue en la scene description.
¿Qué pasa con los descendientes de un prim inactivo?
No se componen ni se visitan.
¿Puede una capa más fuerte reactivar un prim desactivado?
Sí, sobreescribiendo la metadata active.
Model kinds Kind
Kind es metadata a nivel de prim — no un tipo de schema — que clasifica el rol de un prim dentro de la jerarquía de modelo.
- component — asset autocontenido y referenceable; hoja del árbol de modelos.
- group / assembly — unidades organizativas de models relacionados; assembly combina varias partes en una entidad mayor.
- subcomponent — outlier: no es un model kind, solo marca nodos interiores relevantes dentro de un component (que no puede contener otros components).
from pxr import Usd, Kind
model_api = Usd.ModelAPI(prim)
model_api.SetKind(Kind.Tokens.component)
model_api.GetKind()
prim.IsModel() # predicado: Usd.PrimIsModel
OjoTodos los ancestros de un component correctamente organizado deben ser group o assembly — los kinds son extensibles, pero eso rompe portabilidad si quien consume el contenido no conoce la taxonomía custom.
Autoevaluación
¿Qué diferencia component de subcomponent?
Component es un model (hoja, referenceable); subcomponent no es un model kind, solo marca un nodo interior dentro de un component.
¿Qué kind deben tener todos los padres de un component?
group o assembly.
Custom properties
Propiedades definidas por el usuario, fuera de cualquier schema. custom=True es solo metadata informativa: no cambia el comportamiento del attribute.
- Custom properties vs. schemas custom: properties son rápidas y flexibles sin planificación previa; un schema requiere más diseño pero estandariza y agrupa datos de forma reutilizable.
- Como USD no tiene structs nativos, los namespaces anidados (
organización:grupo:propiedad) son la convención estándar para agrupar datos compuestos.
attr = prim.CreateAttribute(
"acme:sensor:temperature", Sdf.ValueTypeNames.Float, custom=True
)
attr.IsCustom() # True
attr.SetDocumentation("Temperatura del sensor, en °C")
OjoPreferir custom properties sobre la metadata customData para prototipar: customData es un diccionario composable más costoso de resolver en value resolution.
Autoevaluación
¿Qué hace realmente custom=True?
Nada a nivel funcional; es solo metadata informativa.
¿Por qué usar namespaces en el nombre de una propiedad?
Para evitar colisiones y agrupar datos compuestos, ya que USD no tiene structs nativos.
Primvars UsdGeom.PrimvarsAPI
"Primitive variables": attributes especiales bindeados a primitivas geométricas y disponibles para los shaders, con interpolación por vértice/cara y herencia por namespace.
- Usos típicos: UVs, vertex colors, datos de deformación/animación.
- Modos de interpolación:
constant (un valor para todo el gprim), uniform (uno por cara), vertex (uno por punto).
primvar_api = UsdGeom.PrimvarsAPI(prim)
primvar_api.CreatePrimvar(
"displayColor", Sdf.ValueTypeNames.Color3fArray, interpolation="vertex"
).Set([Gf.Vec3f(0.0, 1.0, 0.0)])
Autoevaluación
¿Qué problema resuelven los primvars que un attribute normal no resuelve?
Bind de datos a geometría para shaders, con interpolación por vértice/cara y herencia por namespace.
¿Qué interpolación usarías para vertex colors por vértice?
vertex.
Units
No toda la metadata de unidades se reconcilia igual entre capas: timeCodesPerSecond se reescala automáticamente; upAxis, metersPerUnit y kilogramsPerUnit no — los valores geométricos se copian literalmente sin conversión.
- Fallbacks si no se autora nada:
metersPerUnit = 0.01 (cm), upAxis = "Y".
- Tabla de metersPerUnit: km=1000, m=1.0, cm=0.01, mm=0.001, in=0.0254, ft=0.3048.
UsdGeom.SetStageMetersPerUnit(stage, 0.0254) # pulgadas
UsdGeom.SetStageUpAxis(stage, UsdGeom.Tokens.z)
UsdPhysics.SetStageKilogramsPerUnit(stage, 0.001) # kg vía UsdPhysics, no UsdGeom
OjoUn cubo de 1m autorado en cm (size=100, MPU=0.01) referenciado en una escena en mm (MPU=0.001) aparece 100x más chico: el valor 100 se copia literal y 100×0.001 = 0.1m. No hay conversión automática — es responsabilidad de quien ensambla la escena.
Autoevaluación
¿Qué metadata de unidades SÍ se reconcilia automáticamente?
timeCodesPerSecond.
¿Cuál es el fallback de metersPerUnit si no se autora nada?
0.01 (centímetros).
¿Qué módulo expone la API de kilogramsPerUnit?
UsdPhysics, no UsdGeom.
Value resolution
Cómo USD determina el valor final de una property o metadata combinando todas las capas que opinan sobre ella. No es lo mismo que composición.
- La composición se cachea por prim; la value resolution no se cachea — se recalcula en cada
Get() (usar UsdAttributeQuery para cachear manualmente).
- Reglas por tipo de dato: metadata general gana la opinión más fuerte;
customData se combina elemento por elemento (merge por key); relationships combinan todos los targets vía list-editing.
attr.Get() # == Get(Usd.TimeCode.Default()) -> valor NO animado
attr.Get(100) # valor resuelto en el timecode 100
attr.Get(Usd.TimeCode.EarliestTime()) # primer sample real
OjoTrampa clásica: Get() sin argumento devuelve el valor default, no el primer frame animado. Para animación real hay que pasar un timecode explícito o EarliestTime(). Pedir un tiempo anterior al primer sample devuelve (clamped) ese primer sample.
Autoevaluación
¿Se cachea la value resolution como la composición?
No; para cachearla manualmente se usa UsdAttributeQuery.
¿Cómo se resuelve customData entre capas?
Merge por key: gana la opinión más fuerte para cada key individual, no todo-o-nada.
¿Qué devuelve Get() sin argumento si el stage tiene animación?
El valor default, no animado — una trampa común.
Stage traversal Usd.PrimRange
Recorrer el scenegraph en profundidad (depth-first). Stage.Traverse() es un wrapper que arranca en el pseudo-root; Usd.PrimRange(prim) arranca en un prim dado.
- Predicados combinables con operadores bitwise (
&, |, ~) — nunca and/or/not.
- Predicado default de
Traverse(): active + loaded + defined + no abstracto.
PruneChildren() sobre el iterador salta la visita a todo un subárbol.
predicate = Usd.PrimIsActive & Usd.PrimIsLoaded # bitwise, no 'and'
stage.Traverse() # con predicado default
stage.TraverseAll() # sin filtrar, incluye inactive/abstract
it = iter(Usd.PrimRange(root_prim, predicate))
for prim in it:
if prim.GetName() == "Hidden":
it.PruneChildren()
OjoUsd.PrimIsActive and Usd.PrimIsLoaded no hace lo que parece — en Python evalúa el segundo operando y descarta el primero. El combinador correcto es & (bitwise), típica trampa de examen.
Autoevaluación
¿Cómo se combinan predicados de traversal correctamente?
Con operadores bitwise (&, |, ~), nunca con and/or/not.
¿Qué hace PruneChildren()?
Salta la visita a todos los descendientes del prim actual del iterador.
¿Qué predicados incluye el traversal por defecto?
Active, Loaded, Defined y no abstracto.
Hydra
La arquitectura de rendering de OpenUSD: el puente entre los datos de escena y un backend de render concreto.
- Scene delegate — provee la información de la escena.
- Render index — rastrea cambios y gestiona la escena a renderizar.
- Render delegate — combina render index + scene delegate para generar la imagen final (ej. HdStorm, usado por
usdview; también Arnold, RenderMan vía plugins).
OjoEsta separación en tres piezas es lo que permite enchufar distintos renderers de terceros sin tocar los datos de escena.
Autoevaluación
¿Cuáles son las tres partes de Hydra?
Scene delegate, render index y render delegate.
¿Qué renderer usa usdview por defecto?
HdStorm.