Las películas, los juegos y otras producciones gráficas en 3D suelen generar, almacenar y transmitir gran cantidad de datos, que pueden proceder de diversos softwares (como Unreal Engine, Maya, Houdini o Blender) del proceso artístico, cada uno con su propia forma de descripción de escenas.
Universal Scene Description (USD) es un formato de intercambio de código abierto desarrollado por Pixar para abordar la necesidad de intercambiar y aumentar de forma sólida y escalable escenas 3D arbitrarias que estén compuestas de muchos recursos elementales. USD no solo proporciona un amplio conjunto de herramientas para leer, escribir, editar y previsualizar rápidamente sombreado y geometría 3D, sino que también permite intercambiar recursos elementales (por ejemplo, modelos) o animaciones.
A diferencia de otros paquetes de intercambio, USD también permite ensamblar y organizar cualquier número de recursos en decorados, escenas y planos virtuales. A continuación, puedes transmitirlos de una aplicación a otra y editarlos de forma no destructiva (como anulaciones), con una API única y coherente y en un único grafo de escena.
¿Por qué usar USD?
USD proporciona un lenguaje común para mover grandes cantidades de datos entre varias aplicaciones 3D, lo que aporta flexibilidad a la hora de tomar decisiones sobre el proceso artístico y facilita la colaboración entre varios artistas 3D (animadores, artistas de iluminación o sombreado, modeladores, artistas de efectos especiales, etc.) mediante métodos iterativos y no destructivos.
Compatibilidad con USD en Unreal Engine
Unreal Engine ofrece compatibilidad con USD a través del panel Escenario USD y los procesos de trabajo bidireccionales de Python.
Ventana Escenario USD. Haz clic en la imagen para verla a tamaño completo.
En lugar de convertir los datos USD en recursos nativos de Unreal Engine, como mallas estáticas y materiales, el proceso de trabajo del escenario USD funciona de forma nativa con los datos USD, lo que agiliza la introducción de los datos USD en Unreal Engine, ofrece una visión más clara de la estructura original del contenido USD y gestiona las actualizaciones en tiempo real a medida que se realizan cambios en el archivo USD fuente almacenado en el disco.
El escenario USD dispone de las siguientes funciones:
- Representa datos 3D como «prims»: mallas estáticas, mallas esqueléticas, mallas estáticas con instanciado jerárquico, materiales, luces, cámaras, variantes, animaciones y mezclas de formas.
- Edición de atributos no destructiva.
- Grafo de escena USD y visualización de jerarquías.
- Carga y descarga de contenido mediante cargas.
- Compatibilidad con texturas que tengan superficies de previsualización en USD.
- Compatibilidad con materiales con PreviewSurface y DisplayColor.
- Compatibilidad con complementos de USD como Alembic y Custom path Resolver.
- Funciones de USD compatibles en tiempo de ejecución. Para obtener más información, consulta Compatibilidad de USD en tiempo de ejecución.
- Carga los formatos
.usd,.usda,.usdcy.usdz.
Para obtener más información general sobre Universal Scene Description, consulta la publicación de Pixar Introduction to USD (en español, Introducción a USD).
Para obtener más información sobre cómo utilizar el proceso de trabajo de Python, consulta Secuenciación de comandos de Python.
Acciones admitidas
Importación en Unreal Engine
El contenido que aparece en el escenario USD (mallas estáticas, mallas esqueléticas, luces, follaje y paisajes) se puede importar a Unreal Engine a través de los siguientes métodos:
- Mediante Archivo > Importar al nivel. Este proceso importará tanto los recursos (mallas estáticas, mallas esqueléticas, materiales, texturas, etc.) como los actores.
- Mediante el botón Añadir/Importar del explorador de contenido. Este proceso solo importará recursos.
- Arrastrando y soltando el archivo en el explorador de contenido. Este proceso solo importará recursos.
- Mediante la opción Acción > Importar del editor de escenarios USD. Este proceso importará tanto los recursos como los actores. Una vez finalizado el proceso de importación, los recursos del escenario USD se sustituirán por nuevos actores del explorador de contenido.
Creación y edición de animaciones
Se puede acceder a las animaciones almacenadas en un archivo USD usando la secuencia de nivel asociada que se encuentra en el panel Propiedades del USDStageActor.
Abre la secuencia de nivel seleccionando el nivel de escenario USD y haciendo doble clic en la secuencia en el panel Propiedades. Haz clic en la imagen para verla a tamaño completo.
Las animaciones xform de USD se muestran como pistas de transformación dentro de la secuencia de nivel. Otras formas de animación, como los floats, los booleanos y los huesos esqueléticos, se muestran a través de la pista de tiempo. Los datos de animación USD de la imagen anterior se representan como un par clave-valor en cada código de tiempo durante la animación.
A través de la secuencia de nivel generada en el escenario USD, puedes vincularte a un actor generado en el escenario USD y añadir animación adicional mediante una pista de transformación.
Compatibilidad con el tiempo de ejecución de USD
Unreal Engine permite cargar archivos USD en tiempo de ejecución llamando al nodo de Blueprint Set Root Layer en un actor de escenario USD dentro del nivel.
El nodo Set Root Layer. Haz clic en la imagen para verla a tamaño completo.
Este nodo crea los recursos necesarios y genera actores y componentes en el nivel, tal y como se hace en el editor. Entre las funciones adicionales de Blueprint para controlar diversas propiedades de los actores de escenario USD se incluyen las siguientes:
| Función de Blueprint | Descripción |
|---|---|
| Obtener recursos generados | Obtiene los recursos generados para un prim dentro de una ruta de prim determinada y los coloca en una matriz. Usa un actor de escenario USD y una ruta de prim como entradas. |
| Obtener componentes generados | Obtiene el componente generado para un prim dentro de una ruta de prim determinada. Usa un actor de escenario USD y una ruta de prim como entradas. |
| Obtener ruta del prim de origen | Obtiene la ruta del prim de un objeto determinado en el escenario USD. Usa un actor de escenario USD y una referencia de objeto como entradas. |
| Obtener tiempo | Obtiene la marca de tiempo actual dentro del actor de escenario USD de destino. Toma un actor de escenario USD como objetivo. |
| Establecer carga inicial para cargar | Establece la carga inicial que se va a cargar. Usa un actor de escenario USD como entrada y ofrece las siguientes opciones.
|
| Establecer Purpose para cargar | Establece el Purpose inicial que se va a cargar. Usa un actor de escenario USD y un entero como entrada.
|
| Establecer contexto de renderizado | Define el contexto de renderizado de un escenario USD. Toma un actor de escenario USD como objetivo y una a un contexto de renderizado como entrada. |
| Establecer tiempo | Define la marca de tiempo actual de un escenario USD. Toma un actor de escenario USD como objetivo y un valor float como entrada. |
Para obtener más información sobre el atributo Purpose y otros términos relacionados con USD, consulta el glosario de USD de Pixar.
Este proceso permite crear aplicaciones capaces de cargar y mostrar el contenido de un archivo USD en tiempo de ejecución.
Para activar el importador de USD en tiempo de ejecución, añade la siguiente línea a tu archivo Project.Target.cs ubicado en la carpeta UE_(version)\Engine\Source, en el que «Project» corresponde al nombre de tu proyecto:
GlobalDefinitions.Add("FORCE_ANSI_ALLOCATOR=1");
Por ejemplo:
public class YourProjectTarget : TargetRules
{
public YourProjectTarget( TargetInfo Target) : base(Target)
{
Type = TargetType.Game;
DefaultBuildSettings = BuildSettingsVersion.V2;
ExtraModuleNames.AddRange( new string[] { "YourProject" } );
GlobalDefinitions.Add("FORCE_ANSI_ALLOCATOR=1");
}
}
Compatibilidad con el lenguaje de definición de materiales (MDL) de Nvidia
Unreal Engine es compatible con los materiales de superficie del MDL mediante el esquema USD del MDL de Nvidia. Para obtener más información sobre el MDL de Nvidia, consulta el artículo Atributos del sombreador USD de Nvidia.
Compatibilidad con la edición multiusuario
La edición multiusuario es compatible con muchas operaciones de escenario USD, incluidas las siguientes:
- Adición y eliminación de prims.
- Modificación de nombres de prims.
- Edición de atributos prim.
- Activación o desactivación de la visibilidad.
- Acceso, salida o cambio del escenario actual.
Para que tu proyecto de USD sea multiusuario, activa el complemento USD Multi-User synchronization. Para obtener más información sobre cómo trabajar con complementos, consulta Working with Plugins.
La edición multiusuario de USD sincroniza la propiedad Capa raíz del escenario USD para cada cliente, lo que garantiza que todos los usuarios tengan los mismos archivos USD. Esto se consigue haciendo que cada cliente abra el mismo escenario USD de forma local, generando recursos y componentes en su propio sistema y, a continuación, sincronizando únicamente las operaciones realizadas en esos recursos.
Durante una sesión de edición multiusuario, es importante que todos los usuarios accedan a los archivos USD a través de la misma ruta de archivo. Para asegurarte de que todos los clientes puedan acceder a los mismos archivos, recomendamos que los archivos USD de destino se almacenen en la carpeta del proyecto y se gestionen mediante el control de versiones.
Para obtener más información sobre la edición multiusuario en Unreal Engine, consulta Multi-User Editing in Unreal Engine.
No es posible deshacer la eliminación de prims durante una sesión multiusuario.
Activación del complemento de importación de USD
Para empezar a trabajar con un archivo USD en Unreal Editor, tendrás que activar el complemento USD Importer en el menú Complementos. Para obtener más información sobre cómo trabajar con complementos, consulta Working with Plugins.
Después de reiniciar el editor, verás una nueva opción denominada Escenario USD en el menú Ventana > Producción virtual del editor de niveles.
El panel Colocar actores muestra un nuevo Actor de escenario USD que puedes añadir a tu nivel.
Nuevos actores USD disponibles en el panel Colocar Actores.
Uso de USD en Unreal Engine
Trabajar con contenido de USD en Unreal Engine comienza con el editor de escenarios USD y el actor de escenario USD.
El panel Escenario USD.
| Número | Descripción |
|---|---|
| 1 | Jerarquía |
| 2 | Propiedades |
| 3 | Capas |
Proceso de trabajo del escenario USD
Un actor de escenario USD actúa como contenedor del contenido de un archivo USD cargado y proporciona un anclaje para esos datos dentro de tu nivel. Los objetos de escena 3D que se cargan desde el archivo USD y se ven en el visor son totalmente compatibles con la mayoría de las funciones de Unreal Engine, y puedes tratarlos exactamente igual que a otros actores. Puedes añadir prims adicionales que hagan referencia al contenido de otros archivos USD, incluidas las mallas esqueléticas animadas.
Si guardas los cambios realizados en tu escenario USD desde el menú Archivo > Guardar del editor de escenarios USD, estos se volverán a escribir en tu archivo USD.
Para obtener más información sobre cómo trabajar con el escenario USD, consulta Guía de inicio rápido del editor de escenarios USD.
Unreal Engine no crea automáticamente mapas de luz para los recursos cargados en el escenario USD cuando se abre un archivo USD, lo que puede dar lugar a una escena completamente oscura al compilarse la iluminación estática.
Secuenciación de comandos de Python
La secuenciación de comandos de Python con USD ofrece una forma flexible de realizar diversas acciones, como operaciones por lotes y ediciones de escenas, que pueden resultar difíciles o llevar mucho tiempo si se utiliza la interfaz de usuario. Operaciones como ocultar o editar los atributos de un gran número de prims pueden automatizarse rápidamente con una secuencia de comandos flexible de Python ejecutada desde el panel Registro de salida.
Antes de usar Python, debes activar el complemento Python Editor Script. Para obtener más información sobre los complementos, consulta Working with Plugins.
A continuación, puedes utilizar el registro de salida situado en la parte inferior del editor de niveles para ejecutar secuencias de comandos de Python. También puedes abrir el registro de salida con su propio panel desde Ventana > Registro de salida.
Haz clic en la imagen para verla a tamaño completo.
Para obtener más información sobre el uso de secuenciación de comandos de Python con Unreal Engine, consulta Scripting the Unreal Editor Using Python.
Ejemplo de uso de una secuencia de comandos de Python
Cuando se actualizó la versión del SDK de USD que viene con Unreal Engine a la 21.05, se cambiaron los nombres de varios atributos dentro de los esquemas de luz de UsdLux. Para solucionar este problema, Unreal Engine incluye una secuencia de comandos de Python que cambia el nombre de los atributos prim de UsdLux según la convención de nomenclatura de la versión 21.05.
from pxr import Usd, Sdf, UsdLux
import argparse
def rename_spec(layer, edit, prim_path, attribute, prefix_before, prefix_after):
path_before = prim_path.AppendProperty(prefix_before + attribute)
path_after = prim_path.AppendProperty(prefix_after + attribute)
# Hay que comprobarlo siempre, porque añadir un cambio de espacio de nombres que no se pueda aplicar cancelaría todo el lote.
if layer.GetAttributeAtPath(path_before):
print(f"Intentando renombrar '{path_before}' a '{path_after}'")
edit.Add(path_before, path_after)
def rename_specs(layer, edit, prim_path, reverse=False):
prefix_before = 'inputs:' if reverse else ''
prefix_after = '' if reverse else 'inputs:'
# Light
rename_spec(layer, edit, prim_path, 'intensity', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'exposure', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'diffuse', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'specular', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'normalize', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'color', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'enableColorTemperature', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'colorTemperature', prefix_before, prefix_after)
# ShapingAPI
rename_spec(layer, edit, prim_path, 'shaping:focus', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shaping:focusTint', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shaping:cone:angle', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shaping:cone:softness', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shaping:ies:file', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shaping:ies:angleScale', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shaping:ies:normalize', prefix_before, prefix_after)
# ShadowAPI
rename_spec(layer, edit, prim_path, 'shadow:enable', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shadow:color', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shadow:distance', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shadow:falloff', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'shadow:falloffGamma', prefix_before, prefix_after)
# DistantLight
rename_spec(layer, edit, prim_path, 'angle', prefix_before, prefix_after)
# DiskLight, SphereLight y CylinderLight
# Nota: treatAsPoint no debería tener el prefijo 'inputs:', por lo que se ignora.
rename_spec(layer, edit, prim_path, 'radius', prefix_before, prefix_after)
# RectLight
rename_spec(layer, edit, prim_path, 'width', prefix_before, prefix_after)
rename_spec(layer, edit, prim_path, 'height', prefix_before, prefix_after)
# CylinderLight
rename_spec(layer, edit, prim_path, 'length', prefix_before, prefix_after)
# RectLight y DomeLight
rename_spec(layer, edit, prim_path, 'texture:file', prefix_before, prefix_after)
# DomeLight
rename_spec(layer, edit, prim_path, 'texture:format', prefix_before, prefix_after)
def collect_light_prims(prim_path, prim, traverse_variants, light_prim_paths, visited_paths):
if not prim:
Devolución
if prim_path in visited_paths:
Devolución
visited_paths.add(prim_path)
# Recorre manualmente, ya que es posible que cambiemos de variante, lo que invalidaría el iterador stage.Traverse().
for child in prim.GetChildren():
# P. ej. /Root/Prim/Child
child_path = prim_path.AppendChild(child.GetName())
if UsdLux.Light(child):
light_prim_paths.add(child_path)
traversed_grandchildren = False
if traverse_variants:
varsets = child.GetVariantSets()
for varset_name in varsets.GetNames():
varset = varsets.GetVariantSet(varset_name)
original_selection = varset.GetVariantSelection() if varset.HasAuthoredVariantSelection() else None
# Cambia las selecciones solo en la capa de sesión.
with Usd.EditContext(prim.GetStage(), prim.GetStage().GetSessionLayer()):
for variant_name in varset.GetVariantNames():
varset.SetVariantSelection(variant_name)
# P. ej. /Root/Prim/Child{VarName=Var}
varchild_path = child_path.AppendVariantSelection(varset_name, variant_name)
collect_light_prims(varchild_path, child, traverse_variants, light_prim_paths, visited_paths)
traversed_grandchildren = True
if original_selection:
varset.SetVariantSelection(original_selection)
else:
varset.ClearVariantSelection()
if not traversed_grandchildren:
collect_light_prims(child_path, child, traverse_variants, light_prim_paths, visited_paths)
def update_lights_on_stage(stage_root, traverse_variants=False, reverse=False):
""" Recorre el escenario con la capa raíz `stage_root` y actualiza los atributos de los prims de luz a/desde la versión 21.05 de USD.
En este caso, se trata de recorrer el escenario compuesto y recopilar las rutas a los prims que son luces de UsdLux
(alternando variantes o no según el argumento de entrada) y, más adelante, recorriendo todas las capas
del escenario y cambiando el nombre de todas las especificaciones de los atributos prim de luz a la versión 21.05 (añadiendo el prefijo 'inputs:')
o al esquema anterior a la versión 21.05 (eliminando el prefijo 'inputs:').
Recorremos primero el escenario compuesto para asegurarnos de que estamos modificando exclusivamente atributos prim de luz de UsdLux,
evitando modificaciones en el atributo «radius» de una esfera, por ejemplo:
"""
stage = Usd.Stage.Open(stage_root, Usd.Stage.LoadAll)
layers_to_traverse = stage.GetUsedLayers(True)
# Recopila los prims de UsdLux en el escenario compuesto.
light_prim_paths = set()
visited_paths = set()
collect_light_prims(Sdf.Path("/"), stage.GetPseudoRoot(), traverse_variants, light_prim_paths, visited_paths)
print("Prims de luz recogidos:")
for l in light_prim_paths:
print(f"\t{l}")
# Recorre todas las capas y cambia el nombre de todos los atributos relevantes de los prims de luz.
visited_paths = set()
for layer in layers_to_traverse:
# Agrupa todas las operaciones de cambio de nombre de esta capa en una sola edición de espacio de nombres.
edit = Sdf.BatchNamespaceEdit()
def visit_path(path):
attr_spec = layer.GetAttributeAtPath(path)
if attr_spec:
prim_path = attr_spec.owner.path
# Visita cada prim solo una vez, ya que nos encargaremos de todas las propiedades de UsdLux a la vez.
if prim_path in visited_paths:
Devolución
visited_paths.add(prim_path)
if prim_path in light_prim_paths:
rename_specs(layer, edit, prim_path, reverse)
layer.Traverse("/", visit_path)
if len(edit.edits) == 0:
print(f"No hay nada que renombrar en la capa '{layer.identifier}'")
else:
if layer.CanApply(edit):
layer.Apply(edit)
print(f"Cambio aplicado a la capa '{layer.identifier}'")
else:
print(f"No se ha podido aplicar el cambio a la capa '{layer.identifier}'")
# Guarda todas las capas.
for layer in layers_to_traverse:
if not layer.anonymous:
layer.Save()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Actualizar prims de luz a la versión 21.05 de USD')
parser.add_argument('root_layer_path', type=str,
help='Ruta completa a la capa raíz del escenario que se va a actualizar, por ejemplo "C:/MyFolder/MyLevel.usda".')
parser.add_argument('--v', '--traverse_variants', dest='traverse_variants', action='store_true',
help='Determina si se deben recorrer las variantes de todos los conjuntos de variantes encontrados al buscar prims de luz.')
parser.add_argument('--r', '--reverse', dest='reverse', action='store_true',
help='Argumento opcional para hacer el cambio inverso: cambia el nombre de los atributos de luz de la versión 21.05 de UsdLux para que sigan el esquema anterior a la versión 21.05.')
args = parser.parse_args()
update_lights_on_stage(args.root_layer_path, args.traverse_variants, args.reverse)
La secuencia de comandos se encuentra en los archivos fuente de USDImporter, ubicados en Engine/Plugins/Importers/USDImporter/Content/Python/usd_unreal/update_lights_to_21_05.py.
Sigue estos pasos para ejecutar la secuencia de comandos desde el registro de salida:
-
Abre el registro de salida seleccionando Ventana > Registro de salida.
-
Haz clic en el desplegable Cmd a la izquierda del campo de la línea de comandos y selecciona Python.
-
Introduce lo siguiente en el campo de la línea de comandos:
"C:\Program Files\Epic Games\UE_4.27\Engine\Plugins\Importers\USDImporter\Content\Python\usd_unreal\update_lights_to_21_05.py" "C:/path/to/root_layer.usda",en la que
"C:/path/to/root_layer.usda"es la ruta a tu archivo USD.La muestra anterior contiene la ruta predeterminada para la instalación de Unreal Engine. Asegúrate de actualizar la ruta si no has instalado tu versión de Unreal Engine en la ubicación predeterminada.
-
Pulsa Intro para ejecutar el comando.