Writing Out a Max Node's Animation
I'm in the midst of working on a Max animation clip saving tool, so I thought I'd share some progress. This is one of the first substantial tools I've worked on since moving to 3Ds Max, from Maya, and it's proving a good learning experience for understanding some of Max's underpinnings. Max is quite different, to Maya, in how it encapsulates an derives an end matrix. At first the 'controller' tracks, used for node transformations, can seem a bit confusing. It can be very powerful, but also can tend make things overly complicated.
One thing to note is, in maxscript, a 'controller' track is a child of something called a subanim. Or another way to look at it is a subanim has a pointer member variable to a controller type, I guess. The key piece of information to take is; Every node's animate-able element has a subanim class, even if there's no active controller assigned to it. So when collecting animation data you can run through all the subanim's and be ensured you will get all the animation data you need.
Now, using the 'getSubAnim' function, we can get all the child subanim tracks for a given node or subanim. We can use bit of recursion and easily loop through the whole subanim tree, getting all animation data.
One thing to note is, in maxscript, a 'controller' track is a child of something called a subanim. Or another way to look at it is a subanim has a pointer member variable to a controller type, I guess. The key piece of information to take is; Every node's animate-able element has a subanim class, even if there's no active controller assigned to it. So when collecting animation data you can run through all the subanim's and be ensured you will get all the animation data you need.
Now, using the 'getSubAnim' function, we can get all the child subanim tracks for a given node or subanim. We can use bit of recursion and easily loop through the whole subanim tree, getting all animation data.
fn doSomethingWithSubAnim theSubAnim printPrefix =( print (printPrefix + "The subanim has a value of ["+(theSubAnim.value as string)+"]") print (printPrefix + "The subanim controller is ["+(theSubAnim.controller as string)+"]") if theSubAnim.controller != undefined then( print (printPrefix + "The sub controller keys ["+(theSubAnim.controller.keys as string)+"]") ) ) fn recurseSubAnims theSubAnim levelStr:"--" =( -- This function's 'theSubAnim' argument can be a node or a subanim. -- as long as it has a .numsubs attribute -- loop to the number of sub animation tracks (.numsubs) for subIndx = 1 to theSubAnim.numSubs do( -- get a handle to the child sub anim at the index number. local childSubAnim = getSubAnim theSubAnim subIndx -- we'll just do some nice printing for now print (levelStr + "> " + childSubAnim.name) doSomethingWithSubAnim childSubAnim (levelStr+"() ") -- call this function again, using childSubAnim now as the element to search for further child subanims recurseSubAnims childSubAnim levelStr:(levelStr+"--") ) ) -- kick off the recursion at the top level with a single selected node recurseSubAnims $
As you can see, we now get all that creamy subanim goodness. In my tool, I've combined this with a script that, in a very similar fashion, recurses a hierarchy tree so I can write out all the animation for a character to XML.
Once you have a subanim track, you can access the .controller property of that subanim to get the controller. If it is not undefined then you can access the .keys property of the controller class.
Here's an example screen of what i'm writing out.
Once you have a subanim track, you can access the .controller property of that subanim to get the controller. If it is not undefined then you can access the .keys property of the controller class.
Here's an example screen of what i'm writing out.
The tool is still a WIP, but the base functionality, based on these methods is there and working nicely, for both saving and loading. Hopefully, when I get it to a more polished level I'll post some more details.