Maya exported fbx with specific material slot order in Unreal

Hi All,

I am trying to export fbx from maya so that the materials assigned to the mesh show up in unreal in a specific order. Maya doesn’t really have a concept of material slot order and so far I could not find a way to wrangle the material order. I’ve seen some threads that refer to adding “skin##” to the material names to force ordering, but was wondering if others have a solution that is name agnostic.

Thanks in advance!

RG

Is there a specific reason that they have to show up in order vs checking name assigned and mat names in engine?

yes. In our case the artists assume that the specific material element will always have a specific material in UE. For example slot one is always brick material, slot two is always metal, slot three is always glass and so on.

I ended up using the “append skin## to material name” method and it seems to work. I was hoping for a more elegant solution.

Hi RG,

The ordering of material slot in UE depends on the ordering of objects in Maya outliner… based from what I see… so I am just curious how “append skin## to material name” method works?

To reorder objects in Maya outliner, use the reorder command.

I have my own fbx exporter and I recently wrote some code to do what you described. You can try my Python code below:

import pymel.core as pm

class OutlinerOrdering:
	def __init__(self):
		# Take a snapshot of outliner ordering on creation
		self.scene_hierarchy = []
		# Top level transforms ordering
		top_level_transforms = pm.ls(assemblies=True)
		self.scene_hierarchy.append(top_level_transforms)
		# Process the Scene
		self._traverse_transforms(top_level_transforms)
	
	def _get_child_transforms(self, obj):
		'''GetChildren() without the shape nodes or other thing, just want child of transform type'''
		childs = []
		if isinstance(obj, pm.nodetypes.Transform):
			# this include joints, constraints etc, even though they are not transforms themselves
			#   they inherit from transform
			for child in obj.getChildren():
				if isinstance(child, pm.nodetypes.Transform):
					childs.append(child)
		return childs
	
	def _traverse_transforms(self, objs):
		'''Recursive function to traverse the objs hierarchy to fill in the self.scene_hierarchy'''
		for o in objs:
			childs = self._get_child_transforms(o)
			if childs:
				self.scene_hierarchy.append(childs)
				self._traverse_transforms(childs)

	def reorder_objs_in_outliner(self, new_order):
		'''
		Pass a list of pynode or object names, to order them in outliner
		
			Parameters:
				new_order (list): A list of pynodes or strings eg.['aaa', 'bbb']
		'''
		new_order = reversed(new_order)
		for obj in new_order:
			if pm.objExists(obj):
				pm.reorder(obj, front=True)

	def restore_outliner_ordering(self):
		for objs in self.scene_hierarchy:
			self.reorder_objs_in_outliner(objs)
	
	def restore(self):
		'''just a shorter name to restore_outliner_ordering'''
		self.restore_outliner_ordering()

You can try it on a test scene:

... Run this line of code first: ...
outliner_ordering = OutlinerOrdering()
... then made some changes to the ordering of objects in the outliner ...
... then run the code below to see how the ordering are restored back to how it was ...
outliner_ordering.restore()

Below is how I use it in my export code:

	# eg.
	# objs = [aaa, bbb, ccc] # these are pymel objects and are ordered the way I want
	# objs = [aaa, ccc, bbb] # I can reorder them 

	# Reorder object in outliner before export
	outliner_ordering = OutlinerOrdering()  # Take a snapshot of current outliner ordering
	outliner_ordering.reorder_objs_in_outliner(objs) # I pass my objs here to reorder them in outliner

	
	# Fbx export settings
	mel.eval('FBXExportSkins -v 1;')
	... etc ...

	# Export Fbx
	pm.select(clear=True)
	pm.select(objs)
	pm.mel.FBXExport(f=path, s=True)

	# Restore outliner ordering after export
	outliner_ordering.restore()
1 Like

Hi Miica! Thanks for the info. I will investigate and respond shortly!

1 Like

I had done that by reordering material slots in unreal engine … not in maya.
I use below method to get slot with index, then reorder them…

class MeshMaterialHelper ():

    @classmethod
    def GetMeshMaterials(cls, pMesh):
        # type: (unreal.StreamableRenderAsset) -> unreal.Array[unreal.SkeletalMaterial] |unreal.Array[unreal.StaticMaterial] | None
        if isinstance(pMesh, unreal.StaticMesh):
            targetMaterials = pMesh.static_materials
        elif isinstance(pMesh, unreal.SkeletalMesh):
            targetMaterials = pMesh.materials
        else:
            return None
        return targetMaterials

# NOTE :
# pSource : unreal.StreamableRenderAsset
sourceMaterials = MeshMaterialHelper.GetMeshMaterials(pSource)

buildSrcMatMapping : collections.Callable[[],dict[unreal.Name, int]] = \
lambda : dict((v,k) for k, v in enumerate(mat for mat in sourceMaterials))
2 Likes