Thursday 29 November 2012

The power of the FilterSettings class

One of the guys from work asked me about this today and I thought I'd post it up here to show you just how you can use the power of the settings object to filter and organize nodes in Maya. In this example we have 2 rigs in the scene and I want to run a function that will scan both hierarchies for nurbsCurves who's name contains 'Ctrl' and match the nodes, then process the matches in pairs. filterSettings is a class designed specifically just to hold a set of args to be passed into the main filters, it's what the presets in the Hierarchy tab use and store for you.

Here we have the 2 Top nodes of both hierarchies selected. This is the CORE FUNCTION of the entire AnimationUI, it's how it processes matched pairs into something usable for the code:

import Red9.core.Red9_CoreUtils as r9Core

#make a settings object and set the internal filter types
filter=r9Core.FilterNode_Settings()
filter.nodeTypes='nurbsCurve'
filter.searchPattern='Ctrl'

#use the processMatchedNodes call to do all the work for you!
matched=r9Core.processMatchedNodes(cmds.ls(sl=True),filterSettings=filter)

#matched is an object which contains MatchedPairs, a list of tuples in
#the form [(source, destination)] This in turn lets us unpack the
#data in one go for processing
for source,dest in matched.MatchedPairs:
 print source
 print dest
The same filter can be passed into most of the Red9 functions and is used extensively across all the code. For example the above code is filtering hierarchies, so if we just wanted to search a single hierarchy we can pass the same filter to the FilterNode class:
filterNode=r9Core.FilterNode(cmds.ls(sl=True),filterSettings=fSet)
filterNode.ProcessFilter()
This is again a key concept in the entire pack so worth looking at if you're intending to use the code. 

cheers

Red

Monday 26 November 2012

Red9 Studio Pack v1.27 - RC candidate :)

Well after a LOT of work v1.27 is pretty much nailed down. Huge list of upgrades both to MetaData systems, PoseLibs and in general across the board. I'm going to be doing a full video sweep of all the toolsets in the next few days and once done I'll push the build out.

A few last minute fixes are still going in but I'm really excited as this build has huge potential. MetaRig is now in full production at work and being battered, hence all the changes at the moment. I really want to nail down the api before shipping this one in case people start to use it internally like we're now doing.

Brief outline of changes:

  • MetaData has multiple expansions and fixes to MetaClass and MetaRig. Too many to write so it's easier to just look through both the unittests and the example files. Some of these calls are to make it easier for you to subclass the code for your own use, particularly the 'getChildren' and '__bindData__' funcs.
  • PoseSaver now fully supports relative pose loading, ie, loading the stored data relative to a given node. This supports projected and absolute modes. Projected is the pose offset relative to the current ground plane, with projected direction and translation, absolute is just that.
  • PoseSaver now supports a PosePointCloud system to allow you to manipulate a rig in world space with geo reference. 
  • PoseSaver UI has had a ton of upgrades to make it more user friendly, mainly in the RMB menu's
  • FilterNode hierarchy filtering now supports an '=' and 'NOT:' operator so you can specify you want all nodes with x attribute where x=6. Or NOT:thisAttr which will exclude all nodes with the given attr. Again, take a look at the unittests
  • Hierarchy tab in the AnimUI now has a RMB bound to the filterPriorities scroll to let you set these yourself and modify the order.
  • SceneReview upgraded
  • AttrMap now capable of storing the attrMap internally on a given node so a rig can have it stored as an attr on itself for re-loading any time you need.
  • MetaNodeUI now supports a double click = select all children from selected system. Expanded RMB menu too.
  • Mirror systems tweaked and finalized in code for mirroring animation and poses. This needs a UI to allow you to set it!

Still looking for more testers and feedback, particularly those on Linux/mac as I've tried to make this buils os independent but have no way of checking myself.

cheers
Red

Friday 9 November 2012

Using MetaClass in your own classes

So in Red9 you have the power of a full MetaData api but how do you then expand and use that outside of the Red9 package? This came up recently with somebody inheriting from r9Meta.MetaClass in their own module outside of Red9. So I thought I give you a few pointers.

The first thing to note is that Red9_Meta builds up a global list of registered classes which inherit from MetaClass. Basically I need to know, when a node is passed into the MetaClass.__new__(), whether it's mClass attr (the string pointer that holds what class to instantiate on create) is in the known inheritance mapping. Think about it, I initialize the correct class object for you but the code needs to know if that class is available and registered in Python, otherwise I can't instantiate it for you.

This data is stored in global RED9_META_REGISTERY and in the Red9 pack that's setup in the Red9.core.__init__ by calling registerMClassInheritanceMapping()

All following!

Ok so Red9 is up and Meta knows about classes which have MetaClass as a base. By the way, this is found using the cls.__subclasses__(). But now you have a class outside of Red9 which is also using MetaClass and inorder for it to work correctly, you need to get that little bugger picked up and inside the RED9_META_REGISTERY!

This is all down to the order in which the modules are initialized. Lets say that you've booted Maya and Red9 is up. But you have a module in scripts which imports and uses Red9_Meta and it's not showing up in the meta registry. This is because until you import that module it won't show up in the subclasses cmd, and when you do import it, Red9 won't have it in the registry as it was imported after Red9 booted. So you need to first import your module, then force it into the RED9_META_REGISTERY by doing the following:

    #=========================================================================
    # Because we're now inheriting from Red9_Meta any reload on any module that
    # is instantiated from Meta will invalidate the RED9_META_REGISTERY. Here
    # we force the update on the Red9 internal registry
    #=========================================================================    
    from Red9.core import Red9_Meta as r9Meta
    r9Meta.registerMClassInheritanceMapping()  
    print '============================================='
    r9Meta.printSubClassRegistry()
    print '============================================='

Hope that makes sense, if not drop me a mail and I'll point you in the right direction!

Red

Tuesday 6 November 2012

Updates.... gearing up for a new release

Been a while since I posted any updates so wanted to keep you all abreast of what's been happening to the pack. There's been huge development gone into the core of this recently, lots of UI updates and workflow cleanup to make it all a bit slicker in general.


PoseSaver has had a lot of work and now lets you load poses in relative space. The idea is that you select a node you know to be part of a saved pose, I then allow you to load the pose such that that selected node remains in place, the pose is loaded relative to it. This has 2 options for rotate and translates which both allow either 'projected' or 'absolute' calculations. Projected does just that, for rotates it calculates the global direction (relative to the current working up axis), in general that's the Y-axis direction. So you select a node, I workout the difference between it's current direction and it's stored direction, then apply the pose to compensate that difference, in effect locking the node in place. If 'absolute' is selected then rather than calculating the general direction, I just apply the pose completely around that selected node, allowing rotate in all axis. Similar thing happens for translates, either relative to the groundplane, or absolute, allowing vertical offsets.


Now like most of the tools the posesaver relies on the filter being set in Tab2 (above). To help I've unlocked the Node Priorities field and allowed you to set those up from selected nodes. The Node Priorities are CRUCIAL for PoseLoading in relative space as I often need to know the order in which transforms are applied. Lets say in a general rig the Hips are a child of the Root ctrl, so if I offset the Hips BEFORE the Root then you end up with double transforms and screwed up data. This is where the priorities come in, in the above, I'm specifying that root_control is processed before hip_control. You only need to set priorities on those groups that may cause this double transform.

You'll also notice that in the searchPattern above there's a new operator 'NOT:' this is way of excluding nodes that match everything else in the filter. So in the above, L_Arm_IKBlend_cont would match the filter 'cont', but because it's also specified as 'NOT:IKIKBlend' it is then excluded. This is a great addition to the filters and is also going in the attribute search as we speak. In fact for the attr search I'm also going to add a '=' operator as well so you can also catch specific attrs with specific values.

MetaData has had more upgrades. Lots of work gone into the core of the MetaClass. mNode in the class is now a property that wraps the MObject itself, so it doesn't matter if you rename of parent the node, the object will always be in sync. I've also allowed the message attribute handler in the _getattribute__ block  to return both sides of any message links. This was needed as I've been testing the idea of casting the HIK characterProperties node to metaData and using it as our internal skeleton definition setup, but that node is wired such that the node is the child not the parent of the joints, hence the change.

Lots of other things happening so I'll keep you posted

cheers

Red