Skip to content

Instantly share code, notes, and snippets.

@realityforge
Forked from timborrelli/ExportFBX.py
Created April 28, 2023 07:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save realityforge/af67e1b00c67867e2e0c47e19fc96d8e to your computer and use it in GitHub Desktop.
Save realityforge/af67e1b00c67867e2e0c47e19fc96d8e to your computer and use it in GitHub Desktop.
FBX Animation Exporter from Mesh Selection
import maya.cmds as cmds
import os as os
import maya.mel as mel
# Description
# This tool will export selected mesh(es) as an FBX
# It will name each export the same as the Maya file you export from, but with the character's namespace replacing the first part of the file name.
# File naming is expected to be "<name of character>_alltheothershit.extension" like "male_idleToWalk.ma"
# USAGE
# put this script in your scripts folder
# make a shelf button or run via python with this:
# import ExportFBX
# ExportFBX.exportSkinnedMesh(cmds.ls(sl=True, o=True), False)
# the first input variable is the mesh that contains the in-game skeleton you want exported
# the second input variable is a boolen that lets the tool know if you want to remove all root motion (works with Rapid Rig Modular Rigs only at the moment, but the getAllCTRLs function can be modified)
def getSkinClusters():
tempDict = {'meshes': [], 'skinClusters': []}
tempDict['meshes'] = cmds.listRelatives((cmds.ls(selection=True)), ad=True, f=True)
skinClusters = cmds.listConnections(tempDict['meshes'], type='skinCluster')
if skinClusters != None:
for skin in skinClusters:
if skin:
if skin not in tempDict['skinClusters']:
tempDict['skinClusters'].append(skin)
return tempDict
def getJoints(curSkinClusters):
joints = []
for skin in curSkinClusters:
for j in cmds.listConnections(skin, type='joint'):
if j not in joints:
joints.append(j)
return joints
def getFBXSettings():
# get current user settings for FBX export and store them
mel.eval('FBXPushSettings;')
def setFBXSettings():
# set user-defined FBX settings back after export
mel.eval('FBXPopSettings;')
def exportFBX(exportFileName, min_time, max_time):
# store current user FBX settings
getFBXSettings()
# export selected as FBX
# Geometry
mel.eval("FBXExportSmoothingGroups -v true")
mel.eval("FBXExportHardEdges -v false")
mel.eval("FBXExportTangents -v false")
mel.eval("FBXExportSmoothMesh -v true")
mel.eval("FBXExportInstances -v false")
mel.eval("FBXExportReferencedAssetsContent -v false")
mel.eval("FBXExportAnimationOnly -v false")
mel.eval("FBXExportBakeComplexAnimation -v true")
mel.eval("FBXExportBakeComplexStart -v " + str(min_time))
mel.eval("FBXExportBakeComplexEnd -v " + str(max_time))
mel.eval("FBXExportBakeComplexStep -v 1")
mel.eval("FBXExportUseSceneName -v false")
mel.eval("FBXExportQuaternion -v euler")
mel.eval("FBXExportShapes -v true")
mel.eval("FBXExportSkins -v true")
# Constraints
mel.eval("FBXExportConstraints -v false")
# Cameras
mel.eval("FBXExportCameras -v false")
# Lights
mel.eval("FBXExportLights -v false")
# Embed Media
mel.eval("FBXExportEmbeddedTextures -v false")
# Connections
mel.eval("FBXExportInputConnections -v false")
# Axis Conversion
mel.eval("FBXExportUpAxis y")
# Version
mel.eval("FBXExportFileVersion -v FBX201600")
mel.eval("FBXExportInAscii -v true")
cmds.file(exportFileName, exportSelected=True, type="FBX export", force=True, prompt=False)
# restore current user FBX settings
setFBXSettings()
def getFilePath(curFile):
oldPath = (os.path.splitext(curFile)[0]).split("/")
newPath = ""
for i in range(len(oldPath) - 1):
newPath += (oldPath[i] + "//")
return newPath
def getFileName(curFile, prefix, fileType, multiExport):
curCharName = curFile.split("/")
newCharName = curCharName[len(curCharName) - 1]
newFileName = (os.path.splitext(newCharName)[0])
if (multiExport):
fileNameSplit = (os.path.splitext(newCharName)[0]).split("_", 1)
newFileName = (prefix.lower() + "_" + fileNameSplit[1])
curFileName = (newFileName + fileType)
print curFileName
return curFileName
def hackNamespacesAtExport(newNamespace, currentNamespace):
print "Unity is dumb"
# set to newNamespace
references = cmds.ls(type='reference', rf=True)
# create namespace if it doesn't exist
# if (not cmds.namespace(ex=newNamespace)):
# cmds.namespace(add=newNamespace)
for ref in references:
try:
print ref
refFileNS = cmds.referenceQuery(ref, ns=True)
if refFileNS == (":" + currentNamespace):
refFilepath = cmds.referenceQuery(ref, f=True)
cmds.file(refFilepath, e=1, namespace=newNamespace)
# delete last namespace for cleanliness
# if ( cmds.namespace(ex=currentNamespace)):
# cmds.namespace(rm=currentNamespace)
finally:
print "nope"
def getAllCTRLs():
CTRLs = [] # get all RRM controls in the scene. assumes they are named with "rig"
CTRLs = cmds.ls('*:rig_MAIN_Ctrl')
return CTRLs
def killRoot(curRoot):
# kill root motion on weapon
cmds.select(curRoot)
cmds.delete(cn=True)
cmds.xform(ro=(0, 0, 0), t=(0, 0, 0))
def killNameSpace(myNameSpace):
cmds.namespace(set=':')
cmds.namespace(set=myNameSpace)
cmds.namespace(rel=True)
def restoreNameSpace():
cmds.namespace(set=':')
cmds.namespace(rel=False)
def exportPrep(exportList, killRootBool, killNameSpaceBool):
min_time = cmds.playbackOptions(q=True, min=True)
max_time = cmds.playbackOptions(q=True, max=True)
curFileFullName = cmds.file(q=True, expandName=True)
exportFilePath = getFilePath(curFileFullName)
multiExport = False
if len(exportList) > 1:
multiExport = True
# kill all transforms on control rig root
if killRootBool:
for CTRL in getAllCTRLs():
cmds.cutKey(CTRL)
killRoot(CTRL)
for char in exportList:
cmds.select(char)
# get export objects
skinData = getSkinClusters()
allJoints = getJoints(skinData['skinClusters'])
# bake FK joints down
if len(allJoints) > 0:
cmds.bakeResults(allJoints, simulation=True, time=(min_time, max_time))
ns = ''
if len(allJoints) > 0:
cmds.select(allJoints, skinData['meshes'])
# get namespace of selected character
ns = allJoints[0].split(":", 1)[0]
else:
cmds.select(char)
# make export file name
exportFileName = getFileName(curFileFullName, ns, ".fbx", multiExport)
# kill namespaces if true
if killNameSpaceBool:
if ns != '':
killNameSpace(ns)
exportFBX((exportFilePath + exportFileName), min_time, max_time)
# restore namespaces if true
if killNameSpaceBool:
if ns != '':
restoreNameSpace()
def exportSkinnedMesh(exportList, killRootBool, killNameSpaceBool):
cmds.undoInfo(openChunk=True)
try:
exportPrep(exportList, killRootBool, killNameSpaceBool)
finally:
# undo err'thang
print "done"
cmds.undoInfo(closeChunk=True)
cmds.undo()
def prepBatch(fileDir):
files = cmds.getFileList(folder=fileDir, filespec='*.ma')
return files
def doBatch(fileDir, exportList, killRootBool, killNameSpaceBool):
files = prepBatch(fileDir)
for currentFile in files:
# open a file
cmds.file(newFile=True, force=True)
cmds.file((fileDir + currentFile), open=True, prompt=True)
exportSkinnedMesh(exportList, killRootBool, killNameSpaceBool)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment