Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@christophercrouzet
Created December 24, 2016 14:03
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save christophercrouzet/e4daa884d4d4e08bce24addfe820af4d to your computer and use it in GitHub Desktop.
Save christophercrouzet/e4daa884d4d4e08bce24addfe820af4d to your computer and use it in GitHub Desktop.
Quick and dirty prototype of a naive animation bake implementation for Autodesk Maya.
#!/usr/bin/env mayapy
import itertools
import math
import random
import timeit
from maya import cmds, OpenMaya, OpenMayaAnim
def _createLocators(count, baseName, parent=None):
"""Create a bunch of locator nodes.
Parameters
----------
count : int
Number of locators to create.
baseName : str
Each transform node is named using this base name suffixed with '1'.
parent : maya.OpenMaya.MFnTransform
Parent transform node or ``None``.
Returns
-------
list of maya.OpenMaya.MFnTransform
The transform nodes of the locators created.
"""
out = []
oParent = (OpenMaya.MObject().kNullObj if parent is None
else parent.object())
dag = OpenMaya.MDagModifier()
for _ in xrange(count):
oTransform = dag.createNode('transform', oParent)
oShape = dag.createNode('locator', oTransform)
transform = OpenMaya.MFnTransform(oTransform)
transform.setName('%s1' % (baseName,))
out.append(transform)
dag.doIt()
return out
def _createRandomAnimationCurves(dg, node, attrs, keyCount,
timeUnit=OpenMaya.MTime.kFilm,
timeRange=(1, 100), valueRange=(-100, 100)):
"""Create a random animation curve for each given attribute.
Parameters
----------
dg : maya.OpenMaya.MDGModifier
DG modifier.
node : maya.OpenMaya.MFnDependencyNode
Node owning the attributes.
attrs : list of str
Attribute names to animate.
keyCount : int
Number of keys to create.
timeUnit : OpenMaya.MTime.Unit
Unit of time to used for the attribute 'timeRange'.
timeRange : (float, float)
Time range in which the keys are to be created.
valueRange : (float, float)
Range of values for the keys.
"""
timeStart, timeEnd = timeRange
step = (timeEnd - timeStart) / keyCount
for attr in attrs:
times = OpenMaya.MTimeArray(keyCount, OpenMaya.MTime())
values = OpenMaya.MDoubleArray(keyCount, 0)
for i in xrange(keyCount):
times.set(OpenMaya.MTime(timeStart + step * (i + 1), timeUnit), i)
values.set(random.uniform(*valueRange), i)
curve = OpenMayaAnim.MFnAnimCurve()
curve.create(node.findPlug(attr), dg)
curve.addKeys(times, values)
def generateScene(count, attrs, keyCount=10, timeUnit=OpenMaya.MTime.kFilm,
timeRange=(1, 100), valueRange=(-100, 100)):
"""Generate the content of the scene.
That is a scene with 'master' locators being randomly animated and 'slave'
locators being constrained to them.
Parameters
----------
count : int
Number of master and slave locators to create.
attrs : list of str
Attributes to animate.
timeUnit : OpenMaya.MTime.Unit
Unit of time to used for the attribute 'timeRange'.
timeRange : (float, float)
Time range in which the keys are to be created.
valueRange : (float, float)
Range of values for the keys.
Returns
-------
list of maya.OpenMaya.MFnTransform
Slave nodes.
"""
dag = OpenMaya.MDagModifier()
masterRoot = OpenMaya.MFnTransform(dag.createNode('transform'))
masterRoot.setName('masters')
masters = _createLocators(count, 'master', masterRoot)
slaveRoot = OpenMaya.MFnTransform(dag.createNode('transform'))
slaveRoot.setName('slaves')
slaves = _createLocators(count, 'slave', slaveRoot)
dag.doIt()
dg = OpenMaya.MDGModifier()
for master in masters:
_createRandomAnimationCurves(dg, master, attrs, keyCount,
timeRange=timeRange)
dg.doIt()
for master, slave in itertools.izip(masters, slaves):
cmds.parentConstraint(master.fullPathName(), slave.fullPathName())
return slaves
def bakeAnimations(plugs, timeUnit=OpenMaya.MTime.kFilm, timeRange=(1, 100),
timeStep=1):
"""Bake the animation of a bunch of plug.
plugs : list of maya.OpenMaya.MPlug
Plugs to bake the animation of.
timeUnit : OpenMaya.MTime.Unit
Unit of time to used for the attribute 'timeRange'.
timeRange : (float, float)
Time range in which the keys are to be created.
timeStep : float
Time step for each sample.
"""
timeStart, timeEnd = timeRange
sampleCount = int(math.floor((timeEnd - timeStart) / timeStep)) + 1
times = OpenMaya.MTimeArray(sampleCount, OpenMaya.MTime())
plugValues = [OpenMaya.MDoubleArray(sampleCount, 0)
for _ in xrange(len(plugs))]
plugsAndValues = zip(plugs, plugValues)
for i in xrange(sampleCount):
time = OpenMaya.MTime(timeStart + i * timeStep, timeUnit)
times.set(time, i)
context = OpenMaya.MDGContext(time)
for plug, values in plugsAndValues:
values.set(plug.asDouble(context), i)
dg = OpenMaya.MDGModifier()
for plug in plugs:
sources = OpenMaya.MPlugArray()
plug.connectedTo(sources, True, False)
for i in xrange(sources.length()):
dg.disconnect(sources[i], plug)
dg.doIt()
for plug, values in itertools.izip(plugs, plugValues):
curve = OpenMayaAnim.MFnAnimCurve()
curve.create(plug, dg)
curve.addKeys(times, values)
dg.doIt()
def run():
locatorCount = 500
attrs = ('tx', 'ty', 'tz', 'rx', 'ry', 'rz')
timeRange = (1, 400)
OpenMaya.MFileIO.newFile(True)
slaves = generateScene(locatorCount, attrs, timeRange=timeRange)
clock = timeit.default_timer
start = clock()
plugs = [slave.findPlug(attr) for slave in slaves for attr in attrs]
bakeAnimations(plugs, timeRange=timeRange)
elapsed = clock() - start
print("%.3f s" % (elapsed,))
if __name__ == '__main__':
import maya.standalone
maya.standalone.initialize()
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment