Esta guía te enseñará a configurar un renderizado capilar para importarlo desde el [sistema heredado de creación de pelo de XGen] de Maya (http://help.autodesk.com/view/MAYAUL/2018/ENU/?guid=GUID-C6324505-BD4F-4FD2-B340-CF99158D4819) para importar en Unreal Engine con un conjunto de atributos compatibles descritos en la documentación Especificación de Alembic para renderizados capilares.
En la creación de los recursos de esta guía se ha usado Maya 2018.6.
Cómo convertir descripciones de XGen heredadas
Conversión de guías en curvas NURBS
Sigue estos pasos para convertir las guías del renderizado capilar en curvas y guardar un conjunto de curvas que coincidan con las guías que quieres transferir.
-
Configura el menú de Maya en Modelado para ver las opciones de menú correctas disponibles.
-
En el menú principal, haz clic en el desplegable Generar y selecciona Editor de XGen.
-
En la ventana XGen, usa la pestaña Utilidades para seleccionar Guías a curvas.
-
Haz clic en Crear curvas.
Una vez completado, el resultado del renderizado capilar debería ser similar al siguiente:
Cómo convertir renderizados capilares en renderizados capilares interactivos de XGen
Si usas una descripción de XGen heredada, tendrás que convertir el renderizado capilar para que sea un renderizado capilar interactivo de XGen. Puedes hacerlo:
-
Seleccionando los nodos de descripción de XGen.
-
En el menú Modelado, usando el menú principal para hacer clic en el desplegableGenerar y seleccionando Convertir en renderizado capilar interactivo.
Cómo exportar descripciones de spline a curvas NURBS
Sigue estos pasos para exportar las descripciones de spline seleccionadas como un archivo de Alembic que se puede importar con los pelos interpolados como curvas NURBS.
-
Selecciona los nodos de descripción de spline de XGen y, desde el menú Modelado, usa el menú principal para hacer clic en el desplegable Generar. En la lista, selecciona Caché > Exportar Caché.
-
En la ventana Exportar caché, configura lo siguiente:
- Periodo de tiempo de caché: ajústalo en Periodo actual.
- Múltiples transformaciones: desactivado.
- Escribir anchura final: activado.
-
Introduce un nombre para tu archivo y selecciona Alembic como tipo de archivo.
- Haz clic en Exportar.
-
Usa el menú Archivo para seleccionar Importar. Esto abrirá la ventana de importación, que puedes usar para seleccionar e importar el archivo de Alembic ('.abc') a tu escena.
Una vez importado, deberías tener una descripción de spline de XGen exportada y guardada como archivo de Alembic e importada con los pelos interpolados como curvas NURBS.
Creación de atributos
Cómo crear atributos de ID de grupo
El pelo interpolado se puede exportar en uno o más grupos. Estos grupos son reconocidos en Unreal Engine para la asignación de materiales únicos.
Usa la siguiente secuencia de comandos al crear atributos de ID de grupo:
from maya import cmds
attr_name = 'groom_group_id'
# NOTA: cambia los siguientes nombres para que reflejen la escena de tu nodo.
groups = ['hair_brows_splineDescription1|SplineGrp0', 'hair_lashes_splineDescription1|SplineGrp0', 'hair_head_splineDescription1|SplineGrp0']
for groom_group_id, group_name in enumerate(groups):
# obtiene curvas debajo de xgGroom
curves = cmds.listRelatives(group_name, ad=True, type='nurbsCurve')
# etiqueta el grupo con el ID de grupo
cmds.addAttr(group_name, longName=attr_name, attributeType='short', defaultValue=groom_group_id, keyable=True)
# añade el ámbito del atributo
# obliga al archivo de Alembic de Maya a exportar los datos como GeometryScope::kConstantScope
cmds.addAttr(group_name, longName='{}_AbcGeomScope'.format(attr_name), dataType='string', keyable=True)
cmds.setAttr('{}.{}_AbcGeomScope'.format(group_name, attr_name), 'con', type='string')
Creación de atributos de guía
Al crear los atributos de guía para tu renderizado capilar, solo las curvas etiquetadas como guías se usan para la simulación en Unreal Engine. Si no se han especificado guías en el archivo de Alembic, un porcentaje de los pelos interpolados se etiquetará internamente como guías durante el proceso de importación a Unreal Engine.
Al importar un renderizado capilar sin guías, se puede definir el porcentaje de pelos interpolados que se etiquetan como guías en las opciones de importación de renderizado capilar. De forma predeterminada, solo se usarán como guías el 10 % del número de pelos.
Utiliza la siguiente secuencia de comandos al crear tus atributos de guía:
from maya import cmds
attr_name = 'groom_guide'
# obtiene curvas debajo de xgGroom
curves = cmds.listRelatives('xgGroom', ad=True, type='nurbsCurve')
# crea un nuevo grupo
guides_group = cmds.createNode('transform', name='guides')
# etiqueta el grupo como groom_guide
cmds.addAttr(guides_group, longName=attr_name, attributeType='short', defaultValue=1, keyable=True)
# obliga al archivo de Alembic de Maya a exportar las curvas como un grupo.
cmds.addAttr(guides_group, longName='riCurves', attributeType='bool', defaultValue=1, keyable=True)
# añade el ámbito del atributo
# obliga al archivo de Alembic de Maya a exportar los datos como GeometryScope::kConstantScope
cmds.addAttr(guides_group, longName='{}_AbcGeomScope'.format(attr_name), dataType='string', keyable=True)
cmds.setAttr('{}.{}_AbcGeomScope'.format(guides_group, attr_name), 'con', type='string')
# curvas padre en el grupo de guías
for curve in curves:
cmds.parent(curve, guides_group, shape=True, relative=True)
Atributo Groom_Width
Para Maya, el valor de anchura tiene un comportamiento especial, a diferencia de otras aplicaciones de DCC que pueden seguir la especificación de Alembic para renderizados capilares para recuperarlos y usarlos para construir el renderizado capilar.
Maya puede exportar valores de anchura directamente en las curvas, por lo que no es necesario exportar un atributo personalizado groom_width; el importador convierte los valores en ese atributo automáticamente. Si el atributo groom_wdith está presente con el renderizado capilar durante la importación a Unreal Engine, no se sobrescribe. Si no se especifica groom_wdith o no se pueden convertir los valores de anchura, el constructor recurrirá a un valor de 1 centímetro.
Exportación a Alembic desde Maya
-
En Maya, selecciona las curvas de guías e ID de grupo que quieras exportar.
Cada nodo debe tener un nombre único.
-
En el menú Modelado, usa el menú principal para hacer clic en el desplegable Caché y selecciona Caché de Alembic > Exportar selección a Alembic.
-
En la ventana Exportar selección, dentro de la categoría Opciones generales, ajusta Periodo de caché como Periodo actual.
-
En la categoría Atributos, escribe el nombre del atributo que quieras añadir a la lista y haz clic en el botón Añadir. Añade los siguientes atributos de esquema:
- groom_group_id
- groom_guide
-
Introduce un nombre de archivo en el cuadro de texto Nombre de archivo y elige Alembic en Tipo de archivo.
-
Haz clic en el botón Exportar selección.
Aplicación de texturas a UV de pelo
Los siguientes pasos y la secuencia de comandos incluida pueden ayudarte a configurar tu propio pelo de XGen para que puedas exportarlo a Unreal Engine y aplicar una textura representada en mechones de pelo individuales.
-
En Maya, usa el menú Modelado para seleccionar Generar > Crear splines de renderizado capilar interactivo.
-
Puedes crear guías y peinar el pelo como quieras para tu proyecto. Cuando hayas terminado, exporta las curvas como una caché de Alembic seleccionando Generar > Caché > Crear nueva caché.
-
Elimina el pelo de XGen ocultándolo o borrándolo. A continuación, vuelve a importar las curvas de pelo exportadas con la malla de origen en la escena de Maya.
-
En función de la escena, tendrás miles de curvas spline agrupadas bajo una curva principal (SplineGrp0 en este ejemplo). Edita esta secuencia de comandos de Python y sustituye los siguientes valores por los de tu proyecto:
- export_directory
- hair_file
- curve_top_group
- uv_mesh
Puedes descargar la secuencia de comandos aquí.
from maya import cmds from maya import OpenMaya import os def create_root_uv_attribute(curves_group, mesh_node, uv_set='map1'): ''' Crea el atributo "groom_root_uv" en un grupo de curvas. ''' # comprueba el grupo de curvas if not cmds.objExists(curves_group): raise RuntimeError('Group not found: "{}"'.format(curves_group)) # agrupa las curvas curve_shapes = cmds.listRelatives(curves_group, shapes=True, noIntermediate=True) curve_shapes = cmds.ls(curve_shapes, type='nurbsCurve') if not curve_shapes: raise RuntimeError('Invalid curves group. No nurbs-curves found in group.') else: print "Curvas encontradas" print curve_shapes # obtiene las raíces de las curvas points = list() for curve_shape in curve_shapes: point = cmds.pointPosition('{}.cv[0]'.format(curve_shape), world=True) points.append(point) # get uvs values = list() uvs = find_closest_uv_point(points, mesh_node, uv_set=uv_set) for u, v in uvs: values.append([u, v, 0]) #print (str(u) + " , " + str(v) ) # crea el atributo name = 'groom_root_uv' cmds.addAttr(curves_group, ln=name, dt='vectorArray') cmds.addAttr(curves_group, ln='{}_AbcGeomScope'.format(name), dt='string') cmds.addAttr(curves_group, ln='{}_AbcType'.format(name), dt='string') cmds.setAttr('{}.{}'.format(curves_group, name), len(values), *values, type='vectorArray') cmds.setAttr('{}.{}_AbcGeomScope'.format(curves_group, name), 'uni', type='string') cmds.setAttr('{}.{}_AbcType'.format(curves_group, name), 'vector2', type='string') return uvs def find_closest_uv_point(points, mesh_node, uv_set='map1'): ''' Encuentra las coordenadas UV de la malla en puntos dados. ''' # comprueba la malla if not cmds.objExists(mesh_node): raise RuntimeError('Node not found: "{}"'.format(mesh_node)) # comprueba uv_set uv_sets = cmds.polyUVSet(mesh_node, q=True, allUVSets=True) if uv_set not in uv_sets: raise RuntimeError('Invalid uv_set provided: "{}"'.format(uv_set)) # obtiene la malla como ruta dag selection_list = OpenMaya.MSelectionList() selection_list.add(mesh_node) mesh_dagpath = OpenMaya.MDagPath() selection_list.getDagPath(0, mesh_dagpath) mesh_dagpath.extendToShape() # establece el conjunto de funciones de la malla fn_mesh = OpenMaya.MFnMesh(mesh_dagpath) uvs = list() for i in range(len(points)): script_util = OpenMaya.MScriptUtil() script_util.createFromDouble(0.0, 0.0) uv_point = script_util.asFloat2Ptr() point = OpenMaya.MPoint(*points[i]) fn_mesh.getUVAtPoint(point, uv_point, OpenMaya.MSpace.kWorld, uv_set) u = OpenMaya.MScriptUtil.getFloat2ArrayItem(uv_point, 0, 0) v = OpenMaya.MScriptUtil.getFloat2ArrayItem(uv_point, 0, 1) uvs.append((u, v)) return uvs def abc_export(filepath, node=None, start_frame=1, end_frame=1, data_format='otawa', uv_write=True): job_command = '-frameRange {} {} '.format(start_frame, end_frame) job_command += '-dataFormat {} '.format(data_format) job_command += '-attr groom_root_uv ' if uv_write: job_command += '-uvWrite ' job_command += '-root {} '.format(node) job_command += '-file {} '.format(filepath) cmds.AbcExport(verbose=True, j=job_command) def main(): export_directory = 'D:/Dev/Ref' hair_file = os.path.join(export_directory, 'hair_export.abc') curve_top_group= 'description1|SplineGrp0' uv_mesh='pPlane1' create_root_uv_attribute( curve_top_group, uv_mesh) abc_export(hair_file, curve_top_group) main() -
En Maya, ejecuta la secuencia de comandos con los valores modificados para generar un nuevo archivo de Alembic ('.abc') que se pueda importar a Unreal Engine.
-
En Unreal Engine, crea un nuevo material usando el modelo de sombreado Pelo. En el grafo de material, añade una expresión de atributos de pelo y conecta los UV raíz a la entrada UV de la muestra de textura.
El atributo
groom_root_uvespecifica los UV de malla subyacente de cada pelo al que está vinculado. Este atributo es opcional y, si no se especifica, se genera automáticamente un UV raíz en el motor mediante una asignación esférica. -
Arrastra el archivo de pelo importado de Alembic al nivel desde el explorador de contenido y asígnale el material de pelo. Deberías terminar con algo parecido a esto:
Asegúrate de que el archivo de pelo de Alembic en el nivel tenga una anchura superior a 0.