-
-
Save realityforge/af67e1b00c67867e2e0c47e19fc96d8e to your computer and use it in GitHub Desktop.
FBX Animation Exporter from Mesh Selection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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