Skip to content

Instantly share code, notes, and snippets.

@Jerakin
Last active January 19, 2018 09:27
Show Gist options
  • Save Jerakin/4b68b9e7209cb0c0b6c6722f708624cd to your computer and use it in GitHub Desktop.
Save Jerakin/4b68b9e7209cb0c0b6c6722f708624cd to your computer and use it in GitHub Desktop.
Script to export custom animation curves from maya to be used in defold
"""
MAYA 2016 Version
Hack for making custom animations in Defold, animate in Maya then export the animation as a curve.
The script will save every frame as a point on the curve, so try to use as few keys in maya as possible.
Set the "animate to" to 1 and the time to how ever long you want the animation to be. Something like below
go.animate("go", "position.x", go.PLAYBACK_LOOP_PINGPONG, 1, vmath.vector(transform_x), 5.0)
go.animate("go", "position.y", go.PLAYBACK_LOOP_PINGPONG, 1, vmath.vector(transform_y), 5.0)
"""
from PySide.QtCore import *
from PySide.QtGui import *
from shiboken import wrapInstance
from maya import OpenMayaUI as omui
import pymel.core as pm
class ExportWindow(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super(ExportWindow, self).__init__(*args, **kwargs)
self.setParent(mayaMainWindow)
self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.WindowStaysOnTopHint)
self.setObjectName('ExportWindowUI_uniqueId')
self.initUI()
self.keyframe_rb.setChecked(True)
self.timeslider_rb.setChecked(True)
self.export_b.clicked.connect(self.export)
def initUI(self):
self.resize(148, 177)
self.windowLayout = QtWidgets.QVBoxLayout(self)
self.windowLayout.setContentsMargins(1, 1, 1, 1)
self.mainLayout = QtWidgets.QVBoxLayout()
self.typeWidget = QtWidgets.QWidget(self)
self.typeLayout = QtWidgets.QVBoxLayout(self.typeWidget)
self.typeLayout.setContentsMargins(1, 1, 1, 1)
self.curve_rb = QtWidgets.QRadioButton(self.typeWidget)
self.keyframe_rb = QtWidgets.QRadioButton(self.typeWidget)
self.typeLayout.addWidget(self.keyframe_rb)
self.typeLayout.addWidget(self.curve_rb)
self.mainLayout.addWidget(self.typeWidget)
self.line = QtWidgets.QFrame(self)
self.line.setFrameShape(QtWidgets.QFrame.HLine)
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.mainLayout.addWidget(self.line)
self.rangeWidget = QtWidgets.QWidget(self)
self.rangeLayout = QtWidgets.QVBoxLayout(self.rangeWidget)
self.rangeLayout.setContentsMargins(1, 1, 1, 1)
self.timeslider_rb = QtWidgets.QRadioButton(self.rangeWidget)
self.rangeLayout.addWidget(self.timeslider_rb)
self.customrange_rb = QtWidgets.QRadioButton(self.rangeWidget)
self.rangeLayout.addWidget(self.customrange_rb)
self.mainLayout.addWidget(self.rangeWidget)
self.framenumberLayout = QtWidgets.QHBoxLayout()
self.framenumberLayout.setSpacing(15)
self.minframe_le = QtWidgets.QLineEdit(self)
self.framenumberLayout.addWidget(self.minframe_le)
self.maxframe_le = QtWidgets.QLineEdit(self)
self.framenumberLayout.addWidget(self.maxframe_le)
self.mainLayout.addLayout(self.framenumberLayout)
self.windowLayout.addLayout(self.mainLayout)
self.line_2 = QtWidgets.QFrame(self)
self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
self.windowLayout.addWidget(self.line_2)
self.export_b = QtWidgets.QPushButton(self)
self.windowLayout.addWidget(self.export_b)
self.textBrowser = QtWidgets.QTextBrowser(self)
self.textBrowser.setLineWrapMode(QtWidgets.QTextEdit.NoWrap)
self.windowLayout.addWidget(self.textBrowser)
self.setWindowTitle("Export")
self.curve_rb.setText("Curve")
self.keyframe_rb.setText("Key Frames")
self.timeslider_rb.setText("Time slider")
self.customrange_rb.setText("Custom range")
self.export_b.setText("Export")
def export(self):
if self.customrange_rb.isChecked():
start = int(self.minframe_le.text())
end = int(self.maxframe_le.text())
else:
start = pm.playbackOptions(minTime=True, query=True)
end = pm.playbackOptions(maxTime=True, query=True)
if self.keyframe_rb.isChecked():
data = defold_format(get_key_frame_data(start, end))
else:
data = defold_format(get_curve_data(start, end))
self.textBrowser.setText(data)
def _anim_keys(ob, start, end):
animation_data = {"translate": {"x": [], "y": [], "z": []}, "scale": {"x": [], "y": [], "z": []}}
for frame in xrange(int(end - start + 1)):
pm.currentTime(start + frame)
trans = ob.getTranslation()
scale = ob.getScale()
animation_data["translate"]["x"].append(round(trans[0], 4))
animation_data["translate"]["y"].append(round(trans[1], 4))
animation_data["translate"]["z"].append(round(trans[2], 4))
animation_data["scale"]["x"].append(round(scale[0], 4))
animation_data["scale"]["y"].append(round(scale[1], 4))
animation_data["scale"]["z"].append(round(scale[2], 4))
return animation_data
def get_key_frame_data(start, end):
animation_data = {}
sel = pm.selected()
for ob in sel:
animation_data[ob] = _anim_keys(ob, start, end)
return animation_data
def get_curve_data(start, end):
anim_data = {}
for sel in pm.selected():
curve_data = {"translate": {"x": [], "y": [], "z": []}}
points = end - start + 1
increment = 1 / points
for p in xrange(int(points)):
trans = pm.pointOnCurve(sel, pr=increment * p)
curve_data["translate"]["x"].append(round(trans[0], 4))
curve_data["translate"]["y"].append(round(trans[1], 4))
curve_data["translate"]["z"].append(round(trans[2], 4))
anim_data[sel] = curve_data
return anim_data
def defold_format(data):
string = ""
for d in data:
string += "-- {}\n".format(d)
if "translate" in data[d]:
t_x = "local transform_x = {" + str(clean_data(data[d]["translate"]["x"]))[1:-1] + "}"
t_y = "local transform_y = {" + str(clean_data(data[d]["translate"]["y"]))[1:-1] + "}"
t_z = "local transform_z = {" + str(clean_data(data[d]["translate"]["z"]))[1:-1] + "}"
string += "{}\n{}\n{}\n\n".format(t_x, t_y, t_z)
if "scale" in data[d]:
s_x = "local scale_x = {" + str(clean_data(data[d]["scale"]["x"]))[1:-1] + "}"
s_y = "local scale_y = {" + str(clean_data(data[d]["scale"]["y"]))[1:-1] + "}"
s_z = "local scale_z = {" + str(clean_data(data[d]["scale"]["z"]))[1:-1] + "}"
string += "{}\n{}\n{}\n\n\n".format(s_x, s_y, s_z)
return string
def clean_data(d):
if len(set(d)) == 1:
return list(set(d))
return d
mayaMainWindowPtr = omui.MQtUtil.mainWindow()
mayaMainWindow = wrapInstance(long(mayaMainWindowPtr), QtWidgets.QWidget)
ui = ExportWindow()
ui.show()
"""
Hack for making custom animations in Defold, animate in Maya then export the animation as a curve.
The script will save every frame as a point on the curve, so try to use as few keys in maya as possible.
Set the "animate to" to 1 and the time to how ever long you want the animation to be. Something like below
go.animate("go", "position.x", go.PLAYBACK_LOOP_PINGPONG, 1, vmath.vector(transform_x), 5.0)
go.animate("go", "position.y", go.PLAYBACK_LOOP_PINGPONG, 1, vmath.vector(transform_y), 5.0)
"""
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from shiboken2 import wrapInstance
from maya import OpenMayaUI as omui
import pymel.core as pm
class ExportWindow(QWidget):
def __init__(self, *args, **kwargs):
super(ExportWindow, self).__init__(*args, **kwargs)
self.setParent(mayaMainWindow)
self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)
self.setObjectName('ExportWindowUI_uniqueId')
self.initUI()
self.keyframe_rb.setChecked(True)
self.timeslider_rb.setChecked(True)
self.export_b.clicked.connect(self.export)
def initUI(self):
self.resize(148, 177)
self.windowLayout = QVBoxLayout(self)
self.windowLayout.setContentsMargins(1, 1, 1, 1)
self.mainLayout = QVBoxLayout()
self.typeWidget = QWidget(self)
self.typeLayout = QVBoxLayout(self.typeWidget)
self.typeLayout.setContentsMargins(1, 1, 1, 1)
self.curve_rb = QRadioButton(self.typeWidget)
self.keyframe_rb = QRadioButton(self.typeWidget)
self.typeLayout.addWidget(self.keyframe_rb)
self.typeLayout.addWidget(self.curve_rb)
self.mainLayout.addWidget(self.typeWidget)
self.line = QFrame(self)
self.line.setFrameShape(QFrame.HLine)
self.line.setFrameShadow(QFrame.Sunken)
self.mainLayout.addWidget(self.line)
self.rangeWidget = QWidget(self)
self.rangeLayout = QVBoxLayout(self.rangeWidget)
self.rangeLayout.setContentsMargins(1, 1, 1, 1)
self.timeslider_rb = QRadioButton(self.rangeWidget)
self.rangeLayout.addWidget(self.timeslider_rb)
self.customrange_rb = QRadioButton(self.rangeWidget)
self.rangeLayout.addWidget(self.customrange_rb)
self.mainLayout.addWidget(self.rangeWidget)
self.framenumberLayout = QHBoxLayout()
self.framenumberLayout.setSpacing(15)
self.minframe_le = QLineEdit(self)
self.framenumberLayout.addWidget(self.minframe_le)
self.maxframe_le = QLineEdit(self)
self.framenumberLayout.addWidget(self.maxframe_le)
self.mainLayout.addLayout(self.framenumberLayout)
self.windowLayout.addLayout(self.mainLayout)
self.line_2 = QFrame(self)
self.line_2.setFrameShape(QFrame.HLine)
self.line_2.setFrameShadow(QFrame.Sunken)
self.windowLayout.addWidget(self.line_2)
self.line_3 = QFrame(self)
self.line_3.setFrameShape(QFrame.HLine)
self.line_3.setFrameShadow(QFrame.Sunken)
self.normalize = QCheckBox()
self.normalize.setText("Normalize Animation")
self.windowLayout.addWidget(self.normalize)
self.windowLayout.addWidget(self.line_3)
self.export_b = QPushButton(self)
self.windowLayout.addWidget(self.export_b)
self.textBrowser = QTextEdit(self)
self.textBrowser.setWordWrapMode(QTextOption.WordWrap)
self.windowLayout.addWidget(self.textBrowser)
self.setWindowTitle("Export")
self.curve_rb.setText("Curve")
self.keyframe_rb.setText("Key Frames")
self.timeslider_rb.setText("Time slider")
self.customrange_rb.setText("Custom range")
self.export_b.setText("Export")
def export(self):
if self.customrange_rb.isChecked():
start = int(self.minframe_le.text())
end = int(self.maxframe_le.text())
else:
start = pm.playbackOptions(minTime=True, query=True)
end = pm.playbackOptions(maxTime=True, query=True)
if self.keyframe_rb.isChecked():
data = get_key_frame_data(start, end)
else:
data = get_curve_data(start, end)
if self.normalize.isChecked():
data = normalize_data(data)
self.textBrowser.setText(defold_format(data))
def normalize_data(anim_data):
normalized_scale_value = 1
for k in anim_data:
data = anim_data[k]
max_value = max(max(data["translate"]["x"]), max(data["translate"]["y"]), max(data["translate"]["z"]))
_scale = normalized_scale_value / max_value
if _scale < normalized_scale_value:
normalized_scale_value = _scale
print("scale", normalized_scale_value)
for k in anim_data:
data = anim_data[k]
x_l = []
y_l = []
z_l = []
for x in data["translate"]["x"]:
x_l.append(x * normalized_scale_value)
for y in data["translate"]["y"]:
y_l.append(y * normalized_scale_value)
for z in data["translate"]["z"]:
z_l.append(z * normalized_scale_value)
data["translate"]["x"] = x_l
data["translate"]["y"] = y_l
data["translate"]["z"] = z_l
return anim_data
def _anim_keys(ob, start, end):
animation_data = {"translate": {"x": [], "y": [], "z": []}, "scale": {"x": [], "y": [], "z": []}}
for frame in xrange(int(end - start + 1)):
pm.currentTime(start + frame)
trans = ob.getTranslation()
scale = ob.getScale()
animation_data["translate"]["x"].append(round(trans[0], 4))
animation_data["translate"]["y"].append(round(trans[1], 4))
animation_data["translate"]["z"].append(round(trans[2], 4))
animation_data["scale"]["x"].append(round(scale[0], 4))
animation_data["scale"]["y"].append(round(scale[1], 4))
animation_data["scale"]["z"].append(round(scale[2], 4))
return animation_data
def get_key_frame_data(start, end):
animation_data = {}
sel = pm.selected()
for ob in sel:
animation_data[ob] = _anim_keys(ob, start, end)
return animation_data
def get_curve_data(start, end):
anim_data = {}
for sel in pm.selected():
curve_data = {"translate": {"x": [], "y": [], "z": []}}
points = end - start + 1
increment = 1 / points
for p in xrange(int(points)):
trans = pm.pointOnCurve(sel, pr=increment * p)
curve_data["translate"]["x"].append(round(trans[0], 4))
curve_data["translate"]["y"].append(round(trans[1], 4))
curve_data["translate"]["z"].append(round(trans[2], 4))
anim_data[sel] = curve_data
return anim_data
def defold_format(data):
string = ""
for d in data:
string += "-- {}\n".format(d)
if "translate" in data[d]:
t_x = "local transform_x = {" + str(clean_data(data[d]["translate"]["x"]))[1:-1] + "}"
t_y = "local transform_y = {" + str(clean_data(data[d]["translate"]["y"]))[1:-1] + "}"
t_z = "local transform_z = {" + str(clean_data(data[d]["translate"]["z"]))[1:-1] + "}"
string += "{}\n{}\n{}\n\n".format(t_x, t_y, t_z)
if "scale" in data[d]:
s_x = "local scale_x = {" + str(clean_data(data[d]["scale"]["x"]))[1:-1] + "}"
s_y = "local scale_y = {" + str(clean_data(data[d]["scale"]["y"]))[1:-1] + "}"
s_z = "local scale_z = {" + str(clean_data(data[d]["scale"]["z"]))[1:-1] + "}"
string += "{}\n{}\n{}\n\n\n".format(s_x, s_y, s_z)
return string
def clean_data(d):
if len(set(d)) == 1:
return list(set(d))
return d
mayaMainWindowPtr = omui.MQtUtil.mainWindow()
mayaMainWindow = wrapInstance(long(mayaMainWindowPtr), QWidget)
ui = ExportWindow()
ui.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment