aboutsummaryrefslogtreecommitdiff
path: root/Core/Scripts/System/ART_FbxExport.py
diff options
context:
space:
mode:
authorMobileMachine\jeremy <[email protected]>2017-06-06 22:59:03 -0400
committerMobileMachine\jeremy <[email protected]>2017-06-06 22:59:03 -0400
commit24725fa8681f906ab44d80687c09fecc171a2896 (patch)
tree312a601df29aca7f8db9f44082d96ebc7a679138 /Core/Scripts/System/ART_FbxExport.py
parentInitial commit (diff)
downloadartv2-24725fa8681f906ab44d80687c09fecc171a2896.tar.xz
artv2-24725fa8681f906ab44d80687c09fecc171a2896.zip
Initial Submission
First submission of current state of ARTv2. Currently considered to be in Alpha. There are a couple of animation tools not implemented yet, and one module not implemented yet, as well as incomplete documentation.
Diffstat (limited to 'Core/Scripts/System/ART_FbxExport.py')
-rw-r--r--Core/Scripts/System/ART_FbxExport.py392
1 files changed, 392 insertions, 0 deletions
diff --git a/Core/Scripts/System/ART_FbxExport.py b/Core/Scripts/System/ART_FbxExport.py
new file mode 100644
index 0000000..d2745b5
--- /dev/null
+++ b/Core/Scripts/System/ART_FbxExport.py
@@ -0,0 +1,392 @@
+import sys
+import os
+import json
+import maya.standalone as std
+import maya.cmds as cmds
+
+
+std.initialize(name='python')
+
+# set up axis to z
+cmds.upAxis(ax='z')
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+def fbx_export():
+
+ # log some basic info about incoming data
+ sys.stdout.write("Opening File:\n")
+ sys.stdout.write(str(sys.argv[1]))
+ sys.stdout.write("Export Data File:\n\n")
+ sys.stdout.write(str(sys.argv[2]))
+ sys.stdout.write("\n\n")
+
+ # open the maya file
+ cmds.file(str(sys.argv[1]), open=True, ignoreVersion=True, force=True, prompt=False)
+
+ # load data back into dict format
+ f = open(str(sys.argv[2]), 'r')
+ sys.stdout.write(str(f))
+ data = json.load(f)
+ f.close()
+
+ # the data is a dictionary of characters and their export information. That data might look like:
+ # character: [[seq1 data], [seq2 data]]
+ # we need to go through each character's data, go through each sequence, and export that sequence out
+ for character in data:
+ sequences = data.get(character)
+ sys.stdout.write("\n\n")
+ sys.stdout.write(str(sequences))
+ sys.stdout.write("\n")
+ sys.stdout.write(str(len(sequences)))
+ sys.stdout.write("\n")
+
+ # sequence data as follows [0-6]:
+ # Export Meshes? Export Morphs? Export Attrs? Which Morphs? Which Attrs? Pre Script? Path? Post Script? Path?
+ # Sequence data [7] as follows:
+ # [character, export?, fbxPath, start, end, fps, rotation interp, sample rate, root export]
+
+ # loop through each sequence in the sequence data
+ for sequence in sequences:
+ exportMesh = sequence[0]
+ exportMorphs = sequence[1]
+ exportAttrs = sequence[2]
+ morphTargets = sequence[3]
+ customAttrs = sequence[4]
+ preScript = sequence[5]
+ postScript = sequence[6]
+ sequenceInfo = sequence[7]
+
+ # PRE-SCRIPT
+ if preScript[0]:
+ sys.stdout.write("\nExecuting Pre-Script...\n")
+ status = executeScript(preScript[1])
+
+ if status:
+ sys.stdout.write("\nPre-Script successfully executed!\n")
+ else:
+ sys.stdout.write("\nPre-Script NOT successfully executed :( \n")
+
+ # if this sequence is marked for export
+ if sequenceInfo[1] == True:
+
+ euler = False
+ quat = True
+
+ # get the outputPath
+ filePath = sequenceInfo[2]
+
+ # get the start and end frame
+ startFrame = sequenceInfo[3]
+ endFrame = sequenceInfo[4]
+
+ # get the fps
+ fps = sequenceInfo[5]
+ sys.stdout.write("\n\n" + str(fps) + "\n\n")
+ cmds.currentUnit(time=str(fps))
+ cmds.refresh()
+
+ # get the rotation interpolation
+ interp = sequenceInfo[6]
+ if interp == "Quaternion Slerp":
+ euler = False
+ quat = True
+ if interp == "Independent Euler-Angle":
+ euler = True
+ quat = False
+
+ # set the fbx export flags
+ setExportFlags(startFrame, endFrame, euler, quat)
+
+ # get the sample rate
+ sample = sequenceInfo[7]
+
+ # get the root export option
+ rootExport = sequenceInfo[8]
+
+ # build selection of what to export
+ toExport = []
+
+ # EXPORT MESHES
+ if exportMesh:
+ # get meshes
+ if cmds.objExists(character + ":ART_RIG_ROOT"):
+ if cmds.objExists(character + ":ART_RIG_ROOT.LOD_0_Meshes"):
+ meshes = cmds.listConnections(character + ":ART_RIG_ROOT.LOD_0_Meshes")
+
+ for mesh in meshes:
+ toExport.append(mesh)
+
+ # EXPORT MORPHS
+ if exportMorphs:
+ for each in morphTargets:
+ if cmds.objExists(each):
+ if (each.partition(":")[0]) == character:
+ conns = cmds.listConnections(each, type="mesh")
+ if conns is not None:
+ toExport.extend(conns)
+
+ # SKELETON
+ skeleton = [character + ":root"]
+ skeleton.extend(reversed(cmds.listRelatives(character + ":root", type='joint', allDescendents=True)))
+ toExport.append(skeleton[0])
+
+ # bake skeleton and blendshapes (using sample rate)
+ cmds.select(skeleton)
+ if exportMorphs:
+ cmds.select(morphTargets, add=True)
+
+ # bake down animation onto skeleton and blendshapes
+ cmds.bakeResults(simulation=True, sb=sample, time=(startFrame, endFrame))
+
+ # run euler filter and fix tangents
+ cmds.select(skeleton)
+ cmds.filterCurve()
+ cmds.selectKey()
+ cmds.keyTangent(itt="linear", ott="linear")
+
+ # deal with custom attrs (deleting if user chose not to export)
+ standardAttrs = ["translateX", "translateY", "translateZ", "rotateX", "rotateY", "rotateZ",
+ "scaleX", "scaleY", "scaleZ", "visibility"]
+ if exportAttrs:
+ available_attrs = cmds.listAttr(skeleton[0], keyable=True)
+ for attr in available_attrs:
+ if attr not in standardAttrs:
+ if (character + ":" + attr) not in customAttrs:
+ sys.stdout.write("\n\n")
+ sys.stdout.write("Removing Attr:")
+ sys.stdout.write(str(attr))
+ sys.stdout.write("\n\n")
+
+ # remove the attribute from the root
+ cmds.deleteAttr(skeleton[0], at=attr)
+
+ # Root Export Options
+ sys.stdout.write("\n\n" + str(rootExport) + "\n\n")
+ if rootExport != "Export Root Animation":
+ if rootExport == "Zero Root":
+ sys.stdout.write("\nZeroing Out Root Animation\n")
+ cmds.cutKey(skeleton[0])
+ attrs = ["translate", "rotate", "scale"]
+ for attr in attrs:
+ try:
+ cmds.disconnectAttr(character + ":driver_root." + attr, character + ":root." + attr)
+ except Exception, e:
+ sys.stdout.write("\n" + str(e) + "\n")
+
+ for zeroAttr in [".tx", ".ty", ".tz", ".rx", ".ry", ".rz"]:
+ cmds.setAttr(character + ":root" + zeroAttr, 0)
+
+ if rootExport == "Zero Root, Keep World Space":
+ sys.stdout.write("\nZeroing Out Root Animation, Keeping World Space on rest of rig\n")
+ # first, find children that need to be locked in place and create a locator for each
+ rootConnections = cmds.listRelatives(skeleton[0], children=True, type="joint")
+ lockNodes = []
+ locators = []
+
+ for conn in rootConnections:
+ lockNodes.append(conn)
+ constraints = []
+
+ for lockNode in lockNodes:
+ loc = cmds.spaceLocator(name=lockNode + "_loc")[0]
+ locators.append(loc)
+ constraint = cmds.parentConstraint(lockNode, loc)[0]
+ constraints.append(constraint)
+
+ sys.stdout.write("Locking down " + lockNode + " to zero out root.")
+ sys.stdout.write("\n")
+
+ # then bake the locators
+ cmds.select(clear=True)
+ for lockNode in lockNodes:
+ cmds.select(lockNode + "_loc", add=True)
+
+ cmds.bakeResults(simulation=True, sb=sample, time=(float(startFrame), float(endFrame)))
+ cmds.delete(constraints)
+
+ # reverse the constraints so the bones are constrained to the locator
+ boneConstraints = []
+ for lockNode in lockNodes:
+ con = cmds.parentConstraint(lockNode + "_loc", lockNode)[0]
+ boneConstraints.append(con)
+
+ # disconnect attrs on root bone
+ attrs = ["translate", "rotate", "scale"]
+ for attr in attrs:
+ try:
+ cmds.disconnectAttr(character + ":driver_root." + attr, character + ":root." + attr)
+ except Exception, e:
+ sys.stdout.write("\n" + str(e) + "\n")
+
+ # cut keys on the root bone
+ cmds.cutKey(skeleton[0])
+ cmds.setAttr(skeleton[0] + ".tx", 0)
+ cmds.setAttr(skeleton[0] + ".ty", 0)
+ cmds.setAttr(skeleton[0] + ".tz", 0)
+ cmds.setAttr(skeleton[0] + ".rx", 0)
+ cmds.setAttr(skeleton[0] + ".ry", 0)
+ cmds.setAttr(skeleton[0] + ".rz", 0)
+
+ # bake bones now in world space
+ cmds.select(clear=True)
+ for lockNode in lockNodes:
+ cmds.select(lockNode, add=True)
+
+ cmds.bakeResults(simulation=True, sb=sample, time=(float(startFrame), float(endFrame)))
+ cmds.delete(boneConstraints)
+
+ # run an euler filter
+ cmds.select(skeleton)
+ cmds.filterCurve()
+
+ # POST - SCRIPT
+ if postScript[0]:
+ sys.stdout.write("\nExecuting Post Script...\n")
+
+ status = executeScript(postScript[1])
+
+ if status:
+ sys.stdout.write("\nPost-Script successfully executed!\n")
+ else:
+ sys.stdout.write("\nPost-Script NOT successfully executed :( \n")
+
+ # EXPORT FBX
+ cmds.select(toExport)
+
+ try:
+ mel.eval("FBXExport -f \"" + filePath + "\" -s")
+ except:
+ cmds.warning("no path specified..")
+
+ # close mayapy
+ os.remove(str(sys.argv[2]))
+ std.uninitialize()
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+def setExportFlags(startFrame, endFrame, euler=False, quat=True):
+
+ # in 2015, if oneClick isn't loaded, it will throw up an error
+ try:
+ cmds.loadPlugin("OneClick.mll")
+ sys.stdout.write("Loaded OneClick plugin.")
+ sys.stdout.write("\n")
+ except Exception, e:
+ sys.stderr.write("unable to load OneClick plugin.")
+ sys.stderr.write("\n")
+
+ try:
+ cmds.loadPlugin("fbxmaya.mll")
+ sys.stdout.write("Loaded FBX plugin.")
+ sys.stdout.write("\n")
+ except Exception, e:
+ sys.stderr.write("unable to load FBX plugin.")
+ sys.stderr.write("\n")
+
+ # Mesh
+ mel.eval("FBXExportSmoothingGroups -v true")
+ mel.eval("FBXExportHardEdges -v false")
+ mel.eval("FBXExportTangents -v false")
+ mel.eval("FBXExportInstances -v false")
+ mel.eval("FBXExportInAscii -v true")
+ mel.eval("FBXExportSmoothMesh -v false")
+
+ # Animation
+ mel.eval("FBXExportBakeComplexAnimation -v true")
+ mel.eval("FBXExportBakeComplexStart -v " + str(startFrame))
+ mel.eval("FBXExportBakeComplexEnd -v " + str(endFrame))
+ mel.eval("FBXExportReferencedAssetsContent -v true")
+ mel.eval("FBXExportBakeComplexStep -v 1")
+ mel.eval("FBXExportUseSceneName -v false")
+ mel.eval("FBXExportFileVersion -v FBX201400")
+
+ if euler:
+ mel.eval("FBXExportQuaternion -v euler")
+
+ if quat:
+ mel.eval("FBXExportQuaternion -v quaternion")
+
+ mel.eval("FBXExportShapes -v true")
+ mel.eval("FBXExportSkins -v true")
+ mel.eval("FBXExportUpAxis z")
+
+ # garbage we don't want
+ # 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")
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+def executeScript(scriptPath):
+
+ sourceType = ""
+ status = False
+
+ if scriptPath.find(".py") != -1:
+ sourceType = "python"
+
+ if scriptPath.find(".mel") != -1:
+ sourceType = "mel"
+
+ # MEL
+ if sourceType == "mel":
+ try:
+ command = ""
+ # open the file, and for each line in the file, add it to our command string.
+ f = open(scriptPath, 'r')
+ lines = f.readlines()
+ for line in lines:
+ command += line
+
+ import maya.mel as mel
+ mel.eval(command)
+
+ # save the file
+ cmds.file(save=True, type="mayaAscii")
+ status = True
+ except:
+ pass
+
+ # PYTHON
+ if sourceType == "python":
+ try:
+ execfile("" + scriptPath + "")
+
+ # save the file
+ cmds.file(save=True, type="mayaAscii")
+ status = True
+ except:
+ pass
+
+ return status
+
+
+fbx_export()