Este guia mostrará como definir um tratamento para importar do sistema legado de criação de cabelo XGen do Maya de modo a fazer a importação na Unreal Engine com um conjunto de atributos compatíveis descritos na documentação Especificação do Alembic para tratamentos.
O Maya 2018.6 foi usado na criação dos ativos deste guia.
Como converter descrições XGen herdadas
Converta guias em curvas NURBS
Use as etapas a seguir para converter as guias do tratamento em curvas e salvar um conjunto de curvas que correspondam às guias que você deseja transferir.
-
Defina o conjunto de menus do Maya para Modeling" para ver as opções corretas disponíveis.
-
No menu principal, clique no menu suspenso Generate e selecione XGen Editor.
-
Na janela XGen, use a aba Utilities para selecionar Guides to Curves.
-
Clique em Create Curves.
Após a conclusão, a saída do tratamento será semelhante a esta:
Converta tratamentos em tratamentos interativos do XGen
Se estiver usando uma descrição legada do XGen, o tratamento precisará ser convertido em um tratamento interativo do XGen. Você pode fazer isso:
-
Selecione os nós "XGen Description".
-
No conjunto de menus Modeling, use o menu principal para clicar no menu suspenso Generate e selecione Convert to Interactive Groom.
Como exportar descrições de spline para curvas NURBS
Siga estas etapas para exportar as descrições de spline selecionadas como um arquivo Alembic que pode ser importado com os cabelos interpolados como curvas NURBS.
-
Selecione os nós "XGen Spline Description" e, no conjunto de menus Modeling, clique no menu suspenso Generate através do menu principal. Selecione Cache > Export Cache na lista.
-
Na janela Export Cache, defina o seguinte:
- Cache Time Frame: definido como Current Frame
- Multiple Transforms: desabilitado
- Write Final Width: habilitado
-
Insira um nome para o arquivo e selecione Alembic como o tipo de arquivo.
- Clique em Export.
-
Use o menu File para selecionar Import. A janela Import será aberta, podendo ser usada para selecionar e importar o arquivo Alembic ('.abc') para a cena.
Após a importação, você terá uma descrição de spline do XGen que foi exportada e salva como um arquivo Alembic, e importada com os cabelos interpolados como curvas NURBS.
Como criar atributos
Crie atributos de ID do grupo
Cabelos interpolados podem ser exportados em um ou mais grupos. Esses grupos são reconhecidos na Unreal Engine pela atribuição única de material.
Use o seguinte código ao criar atributos de ID de grupo:
no prompt de comando de importação do Maya
attr_name = 'groom_group_id'
# OBSERVAÇÃO: altere os nomes a seguir de acordo com a cena do nó.
groups = ['hair_brows_splineDescription1|SplineGrp0', 'hair_lashes_splineDescription1|SplineGrp0', 'hair_head_splineDescription1|SplineGrp0']
for groom_group_id, group_name in enumerate(groups):
# obtenha curvas em xgGroom
curves = cmds.listRelatives(group_name, ad=True, type='nurbsCurve')
# grupo de tags com id do grupo
cmds.addAttr(group_name, longName=attr_name, attributeType='short', defaultValue=groom_group_id, keyable=True)
# adicione um escopo de atributo
# Obriga o Alembic do Maya a exportar os dados 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')
Crie atributos de guia
Ao criar os atributos de guia para o tratamento, apenas as curvas marcadas como guide são usadas para simulação na Unreal Engine. Se não houver guias especificadas no arquivo Alembic, uma porcentagem dos cabelos interpolados será marcada internamente como guias durante o processo de importação para a Unreal Engine.
Ao importar um tratamento sem guias, a porcentagem de cabelos interpolados marcados como guias pode ser definida usando as opções de importação do tratamento. Por padrão, apenas 10% do número de fios de cabelo serão usados como guias.
Use o seguinte código ao criar os atributos de guia:
no prompt de comando de importação do Maya
attr_name = 'groom_guide'
# obtenha curvas em xgGroom
curves = cmds.listRelatives('xgGroom', ad=True, type='nurbsCurve')
# crie um novo grupo
guides_group = cmds.createNode('transform', name='guides')
# marque o grupo como groom_guide
cmds.addAttr(guides_group, longName=attr_name, attributeType='short', defaultValue=1, keyable=True)
# Obriga o Alembic do Maya a exportar as curvas como um grupo.
cmds.addAttr(guides_group, longName='riCurves', attributeType='bool', defaultValue=1, keyable=True)
# adicione um escopo de atributo
# Obriga o Alembic do Maya a exportar os dados 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-pai no grupo de guias
para a curva em curvas:
cmds.parent(curve, guides_group, shape=True, relative=True)
Atributo Groom_Width
No Maya, o valor da largura tem um comportamento especial, ao contrário de outros aplicativos criação de conteúdo digital que podem seguir a especificação do Alembic para tratamentos para recuperá-los e usá-los na compilação do tratamento.
O Maya pode exportar valores de largura diretamente nas curvas para que não seja necessário exportar um atributo "groom_width" personalizado. O importador converte esses valores nesse atributo automaticamente. Caso o atributo "groom_wdith" esteja presente com o tratamento durante a importação para a Unreal Engine, ele não será substituído. Se "groom_wdith" não for especificado, ou os valores de largura não puderem ser convertidos, o compilador usará o valor de 1 centímetro.
Como exportar para o Alembic do Maya
-
No Maya, selecione as guias e as curvas Group_ID que deseja exportar.
Cada nó deve ter um nome exclusivo.
-
No conjunto de menus Modeling, use o menu principal para clicar no menu suspenso Cache e selecione Alembic Cache > Export Selection to Alembic.
-
Na janela Export Selection, na categoria General Options, defina Cache time range para Current Frame.
-
Na categoria Attributes, digite o nome do Attribute que deseja adicionar à lista e clique no botão Add. Adicione os seguintes atributos de esquema:
- groom_group_id
- groom_guide
-
Insira o nome do arquivo na caixa de texto File name e defina Files of type para Alembic.
-
Clique no botão Exportar Seleção.
Como aplicar texturas a UV de cabelo
As etapas a seguir e o código incluído podem ajudar a configurar seu próprio cabelo XGen, que pode ser exportado para a Unreal Engine e ter uma textura aplicada representada em fios de cabelo individuais.
-
No Maya, use o menu Modeling para selecionar Generate > Create Interactive Groom Splines.
-
Você pode criar guias e pentear o cabelo como quiser para o projeto. Quando tudo estiver pronto, exporte as curvas como um Cache Alembic selecionando Generate > Cache > Create New Cache.
-
Remova o cabelo XGen ocultando-o ou excluindo-o. Em seguida, importe novamente as curvas de cabelo exportadas com a malha de origem na cena Maya.
-
Dependendo da cena, você terá milhares de curvas de spline como pais sob uma curva superior, SplineGrp0 neste exemplo. Edite o seguinte código Python e substitua os valores a seguir pelos do projeto:
- export_directory
- hair_file
- curve_top_group
- uv_mesh
Você pode baixar o código abaixo here.
no prompt de comando de importação do Maya na importação do Maya OpenMaya so de importação def create_root_uv_attribute(curves_group, mesh_node, uv_set='map1'): ''' Crie o atributo "groom_root_uv" no grupo de curvas. ''' # verifique o grupo de curvas if not cmds.objExists(curves_group): raise RuntimeError('Grupo não encontrado: "{}"'.format(curves_group)) # Obtenha curvas no grupo curve_shapes = cmds.listRelatives(curves_group, shapes=True, noIntermediate=True) curve_shapes = cmds.ls(curve_shapes, type='nurbsCurve') if not curve_shapes: raise RuntimeError('Grupo de curvas inválido. Nenhuma curva NURBS encontrada no grupo.') else: print "curvas encontradas" print curve_shapes # obtenha raízes de curva points = list() for curve_shape in curve_shapes: point = cmds.pointPosition('{}.cv[0]'.format(curve_shape), world=True) points.append(point) # obtenha 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) ) # crie 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'): ''' Encontra as coordenadas UV da malha em determinados pontos. ''' # confira a malha if not cmds.objExists(mesh_node): raise RuntimeError('Nó não encontrado: "{}"'.format(mesh_node)) # verifique uv_set uv_sets = cmds.polyUVSet(mesh_node, q=True, allUVSets=True) if uv_set not in uv_sets: raise RuntimeError('uv_set inválido fornecido: "{}"'.format(uv_set)) # obtenha a malha como dag-path selection_list = OpenMaya.MSelectionList() selection_list.add(mesh_node) mesh_dagpath = OpenMaya.MDagPath() selection_list.getDagPath(0, mesh_dagpath) mesh_dagpath.extendToShape() # obtenha o conjunto de funções da malha 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() -
No Maya, execute o código com os valores alterados para gerar um arquivo Alembic ('.abc') que pode ser importado para a Unreal Engine.
-
Na Unreal Engine, crie um material usando o modelo de sombreamento Hair. No gráfico de material, adicione uma expressão Hair Attributes e conecte o Root UV à entrada UV da amostra de textura.
O atributo "groom_root_uv" especifica por cabelo a malha UV subjacente à qual está anexado. Esse atributo é opcional e, se não for especificado, um UV-raiz será gerado automaticamente na engine usando um mapeamento esférico.
-
Arraste o arquivo Alembic de cabelo importado para o nível a partir do Navegador de Conteúdo e atribua o material de cabelo a ele. No fim, você deverá ter algo mais ou menos assim:
Certifique-se de que o arquivo Alembic de cabelo no nível tem largura maior que 0.