I previously posted about my custom maya node that does some 'pose' based calculations, for use in driving deformations and what not.

I recently found myself wishing I had it to use in 3ds Max. So, I wrote one.
Below I'm just driving three point and orient constraint weights via the output of the node.
This is generally a bit simpler than my Maya version. It just defines two radius' and remaps the angle, between two matrix axis vectors, from 0-1 (or reverse). The Maya node allowed a definition of an ellipse shape for both min and max 'areas', so I could elongate the shape over one axis more than another. However I'm getting good results from just the circular shapes, so I'm happy for now.

To achieve this I wrote a Scripted Manipulator Plugin to draw the shapes, and to store the needed parameters for node associations, to control the shape and store the output. Then, inside the Scripted plugin, I'm adding a Scripted Controller, on creation, to the Output parameter.  The scripted controller is actually pretty simple:

 /* Float Scripted Controller code that handles 'pose space' calculations. It is assigned to the output of our custom node  The Float Script controller has two node variables assigned to it:         srcObj :        this is essentially 'this' object... the object this controller is assigned to         targObj :       The Target node that we are comparing axese to */  -- the return value... init with invalid value local theOutput = -1.0;  -- make sure the source node is valid if srcObj != undefined then (                  -- make sure the target node is valid         if targObj != undefined then (                          -- this is the angle variable that will be converted to a valid 0-1 output                 local theAngle = 0.0;                                  -- Grab this nodes z axis... we always use the z axis for the source (this) node                 local srcAxis = srcObj.transform.row3                  -- Here we are getting some 'settings' from properties on the target node...                 -- ..here we grab the target axis of the target node based on the drop down ui/property user specification                 local targAxis = [0,0,0]                 if srcObj.TargetAxis == 1 then targAxis = targObj.transform.row1;                 if srcObj.TargetAxis == 2 then targAxis = targObj.transform.row2;                 if srcObj.TargetAxis == 3 then targAxis = targObj.transform.row3;                  -- calculate the angle between the two axes..                  theAngle = (acos (dot targAxis srcAxis ));                  -- again grab more settings from the source node. Here we grab the min and max                 -- angle settings                 local minimum = srcObj.innerRadius;                 local maximum = srcObj.outerRadius;                                  -- Here we are calculating the output based on another node property setting.                 if srcObj.ReverseOutput == false then(                           -- default calculates output as a 0-1 value.. 'inside' the specified cone                         if theAngle < minimum then theOutput  = 1.0;                         else if theAngle > maximum then theOutput = 0.0;                         else theOutput = 1 + -((theAngle - minimum) / (maximum - minimum)) ;                                             )else(                         -- Reverse output is a 0-1... outside the cone..                          if theAngle < minimum then theOutput = 0.0;                         else if theAngle > maximum then theOutput = 1.0;                         else theOutput = ((theAngle - minimum) / (maximum - minimum)) ;                                                                   )         ) ) -- return / set the controller value theOutput ; 
It all seems pretty fast, so that's a plus. I was dubious of the speed needs for something like this using Maxscript and Scripted Controllers, but it seems decent.
 
 
Wow. Almost Ten months of inactivity and two posts within a few hours!

So, recently I finished up a first pass on a GUI idea I've had for a while (though it's mainly a 'picker' at the moment).

I initially did a few prototypes using maxscript, with the dot net wrappers, and also plain c# winforms. However, I could not, easily, achieve some key features I wanted. Or, lets say, they were messier to manage when implementing these features. 
Mainly I wanted  the ability to pan and zoom around. Scale and pan functionality would allow me to really fill a gui 'page' with lots of stuff. From there the user can zoom and focus in to the area they are interested in, fingers for example. Out of the 3, WPF definitely handled 'transforming' ui elements the best.

I also wanted to be able to create and edit gui layouts inside the tool window, being able to lay out new button and edit existing ones as needed, even by an animator.

So here's what I ended up with:
In the video I'm using a default Cat Ape rig as an example, then creating and associating nodes with the gui form. 

To achieve this I used WPF for the window and buttons layout code. In fact it is all done in c#, using the .Net api to handle the Max node selections and some callbacks.

WPF uses lovely vector graphics to draw its ui elements so the implementation of my zoom functionality works pretty well, other than  the background image looking pixelated when zoomed right in!

For the 'Editing Mode' I had to implement a custom property on a class inherited from a Canvas. I had originally tried to manipulate an InkCanvas to my will, as it already has an 'Editing Mode' and the ability to move and manipulate child UI Elements. However, there were some drawing and selection issues with that that didn't fit what I wanted. 
I was dubious about the complexity on managing a 'state' like this across the drawing elements manually, as this was my first forray into WPF. It worked out pretty well in the end. Implementing it this way allowed me to control the mode changes with all the granularity I needed, and it wasn't that much work.

Again, I used the .Net api for the selection, callbacks and all max scene needs. I did, originally, plan on using maxscript for the max side stuff and exposing events through c#, then hooking them up on the other end, as outlined in this document. However, that code looked a bit messy, management wise, and didn't look like it would scale well. I really wanted to keep it all together and clean. 

After some searching, digging and trial and error I managed to get what I needed from max's .Net dll's. 
Now, it should be noted I am not doing anything fancy with the .Net API here. Mostly, I'm re-cursing the scene tree, grabbed from the Autodesk.Max.IInterface13.COREInterface13 instance, and collecting the IINodes I need. Once I have the IINodes selecting and deselecting becomes very easy.

It was a huge win to have everything in one project and codebase!
All in one VS Project!
All in one VS Project!
I inherited the ui elements I needed from basic WPF classes; buttons, canvas, tabs, etc, in to custom classes that simply add some properties and methods that store IINodes and manage the lists of IINodes.
I also implemented selection and file open callbacks to refresh and validate the nodes in the classes as needed. 

I created two 'types' of buttons the user can add to the gui, seen in the video. The first is a 'Selector', that is associated with a single node via name, and the second is an 'Executor' button, that can select multiple nodes and also run basic maxscript commands via string.  This allows me to be able to create the selection buttons and have 'selection set' and tools buttons.

I use WPF Adorners in Editing Mode to manipulate the with and height of the buttons, relative to their parent canvas. Adorners were a little tricky to get my mushy brain around, as it's basically an invisible layer on top of the ui element, and you have use the 'thumbs' in the Adorner system to drive what you want. However, once you get used to it (or as in my case got a really good example from the net and re-work it to my needs) it makes sense and really didnt need too much maintenance. 

Any 'gui layout' can be saved to loaded from xml files, that simply describe the buttons, tab and properties.

Again this is Pretty first pass stuff. There are lots of things I'd like to add to this in the future, sliders to manipulate properties and auto generate rig buttons to name a couple. For now the foundation is in and working really well. 

Also, it was really nice to use c# for a while. Damn nice language.
 
 
So recently, on the webs of the net, dropped the first gameplay video of Middle Earth : Shadow of Mordor.
I had the great privilege of working on this title while at WB in Seattle. I was a Rigger/Technical Artist on this for around a year, mostly in pre-production... Those orcs look very familiar :D.

It's really, really great to see it, and looking damned sweet. The guys there have really taken it on leaps and bounds over the last year and I'm really excited to see what my old comrades have done, when I get to play it.  It really is such a talented team. Fond memories.
 
 
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.

..read full post
 
 
Just thought I'd share a video of an upcomming title I worked on. Not only was it a blast to work on, it's a blast to play!


 
 
I've been playing about with Maya api, with python, a bit more. I took my experiences from this post on a bit further. The previous node i created, in the mentioned post, had a few downfalls as to useability. The main one was I could only define a radial offset from the comparison axis. I wanted to be able to define a more arbitrary shape for the angle comparison, essentially I wanted to elongate the shape, This would help me define more useable shapes to define as my target pose. If that makes any sense! Anyway here’s the node in action.

The node outputs a 0-1 blended value representing if the axis of the node is within the range set. I've just piped that output into a sphere for visual guide.

This node should aid my rigging in terms of deformations. My main reason for wanting to create this, was a solution to some armor rigging that is needed in work. Here's a super rough, quick test where I'm driving an aim constraint and its up vector node via three volume range nodes.
And here’s the obligatory bicep deformation shot. Again a very rough test, but should help give you the idea... like you needed it!
 
 
I'm starting to look into Communicating between applications from Maya. So If you’re looking to install the COM python module for Maya, here's how I got it working.

Get the appropriate installer here
    For Maya 2012 64 bit get the pywin32-217.win-amd64-py2.6.exe
    For Maya 2012 32 bit get the pywin32-217.win32-py2.6.exe
Run the downloaded executable, it should install to your C:\Python26\Lib\site-packages.
Copy the contents of that folder to your C:\Program Files\Autodesk\Maya2012\Python\lib\site-packages.

That should do it!

Of course be aware of what other packages you had installed previously in both site package folders, if you're concerned about overwriting something.
 
 
..Maybe because I am.
    ls -type "joint" "|*" ;
Sometimes we just need to get something working, and we write functions to get simple pieces of data or whatever. Well I was at my desk recently and the above piece of code just dawned on me. The amount of times I've written code to get all joints at the root of the scene, looping parent queries.... Sometimes I feel stupid.

 
 
If you want to display a custom ui and halt all other maya ui interaction whilst it's open, here’s a script.

This uses Maya’s new-ish layoutDialog ui element, and it basically lists things and returns the user's specification. Nothing special, but it is nice that it basically acts like a confirmDialog.. The code is a bit hacked together as I originally thought I could get a textScrollList, in python, to simply accept data with some *args or **kargs callback functions, but no joy there. So I had to wrap this up in a class and use some class attributes to store and access the needed data on events.

Anyway here's the script. This may not be the cleanest way to do this, but I had to get it working. Hope someone finds it useful.

selectitemdialogui.py
File Size: 3 kb
File Type: py
Download File

 
 
I wrote another custom node, again beholden somewhat to this post, that basically calculates the angle between to vectors.

It takes in two world space matrices and compares specified axis (x,y or z) of the nodes. It returns a ranged, 0-1, value based on user set bounds (actually the node outputs a ranged angle, full angle and dot product). Its really pretty simple but should come in handy.

I have tried to make this setup before, using Maya utility nodes and some elbow grease, but It was always quite cumbersome and I was a bit off with the math, So I thought an api node would be a better bet. So I created a nice self contained node that does it all for you and gave the user a nice display.

Here it is in action. I piped the output into the scale of the cube for visual cue of the output. 
I think i can take this a bit further, I'm thinking of trying to make this calculate a u-v space bounds of a sphere, so i can cut a more complex piece of a sphere to calculate if the vector is inside. We'll see how far i get with that!