Friday, March 6, 2015

Maya Callbacks and References

Working Scenario
The scenario that I'm working with in Maya involves two referenced rigs and creating constraints and message attributes between them. Now since i'm using references in Maya, additional bones, controls or what have you may be created in either reference at any point in time. What I'm doing is creating parent constraints from one rig to the other and anytime new bones or controls are added to the on rig, I need to constrain it to the other rig with relative names automatically. This is where callbacks come into play.

Callback
After the scene is fully Open and all the references are loaded I need to check message attributes to see if one rig is "connected" to another. Here I'm using message attributes to point each rig to one another. The callback looks for this message, if found it will update the connections by creating new constraints for similarly named objects. Now I was originally using the kAfterOpen callback which should fire off after all references are loaded. It does work, but I changed to the scriptJob version, "SceneOpened", that seems to run later than the callback variant, even after viewport processing. The method being called in the callback runs and connects everything just fine. While the scene appeared to be functioning correctly, after saving and reloading the file later, all the constraints were broken and the attributes were missing. I started to panic thinking this was a new bug with saving and references. I posted on the Autodesk beta boards after trying multiple approaches to work around my problem.

The Actual Problem
I spent quite a while doing diffs on the maya ascii files. The file before the callback and the file after the callback. Here I started to notice differences in the referenceEdits. I didn't understand all the formatting so I went on a hunt for the information there. Sadly, the actual documentation that I found had no real detail in the places that I had question about. This archived Post from PosingMantis on cgsociety helped greatly. What I started to realize was that all the operations I was doing during callbacks, while still functioning in the scene afterwards, they were not saving in the referenceEdits. 

Here's an example of what the connections in the refEdits look like before the callbacks. The referenced ball is parentConstrained to the referenced box.

After the callback ran, all of those reference edits were now missing, but like I said everything was still operating and working properly in the scene. This was incredibly misleading. I looked for some more documentation and I found the root of my problems.

File I/O callbacks don't record reference edits

The Solution
If I was a good little tech artist I would have read ALL of the documentation on callbacks. I know what callbacks do, why would I think methods called from them wouldn't record referenceEdits. Sigh. There are specific callbacks you can run after a reference loads and you can record referenceEdits. kAfterSceneReadAndRecordEdits This one probably does precisely what I needed, the others fire off after every referenceLoads which I didn't need. However, after chatting with Brad Clark cofounder of @RigginDojo, I opted for creating a scriptNode that runs the same methods OnDemand after a "SceneOpened" scriptJob, and the scriptNode has a flag to "RecordReferenceEdits". I can also only create this in the scenes that need them.

This still may not be the best way to do it but right now it's what I needed to move forward. I hope this will be helpful to someone as none of the issues I noticed were directly obvious. Good luck!