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!

7 comments:

  1. Great post Randall, I also would love to know if there is a better option to do this, but thanks for working through it, I am glad I could help for now.

    ReplyDelete
  2. Thanks for this, I didn't know about kAfterSceneReadAndRecordEdits - I assumed it was a bug! I think I hacked around it in the past with evalDeferred in the afteropen callback which ended up running my code at a time maya was ready to record reference edits. ie
    def my_after_open_cb():
    pm.evalDeferred("import my_fix; my_fix.run()")

    ReplyDelete
  3. Nice Luke, You know, I considered evalEdeferred, but I wasn't sure if it would still be called within the same scope of time. Good to know. Thanks for following up!

    ReplyDelete
  4. i think i've just encountered this problem. after working on some lighting, i reloaded my scene to apply my tests to the lights and noticed there was a car in my camera viewport that shouldn't be there.
    i switched to perspective virw and realised with horror that all 7 of my referenced cars (from 2 different files) had totally lost their parent constraints, as had a camera PC'ed to one of the cars! they just weren't there in the outliner.

    what i'd like to know is could a callback script refix this error, or am i looking at redoing the linking manually.
    i'm also now worried that my other 4 animations are likely to start suffering at some random time as well.
    i did go back through a few earlier saves and they all seemed to have this issue, even though they had previously been working fine.

    apologies for the slight ramble, but i've been searching all weekend trying to find out why my files broke and your post seemed to shed a bit of light on the possible problem
    cheers
    mark

    ReplyDelete
  5. Hey Mark, one thing to make sure is that you didn't rename anything in the files that you have referenced in. If you did rename, the connections you've made in your scene will break. If you go to File > ReferenceEditor right click your reference > File > List Edits. At the bottom of the dialog that pops open will be missing edits. These are due to not finding objects that originally existed. It will list the objects original names and what connections were made, connections to constraints in your case.

    ReplyDelete
    Replies
    1. Another thing to be on the lookout for is a new group in the outliner with the same namespace as your reference + Foster. It holds any broken constraints and whatnot just in case you fix the reference name later. Don't delete these if you intend on fixing your either renamed or deleted objects.

      Delete
    2. Hey Randall. Thanks for getting back to me. Myself and our own resident melscript expert will have a look into those points you mentioned and see if we can bring this file back from the grave!

      I think i need to be a lot more rigorous with how I treat my refs in future! :)

      Delete