So the last week or two I’ve been writing up a plan for Workbench’s functionality (and, frustratingly, I’m still adding to it, normally just as I’m trying to get to sleep). Seeing as the planning stages of this project are starting to come to a close, I wanted to talk a little bit about my process for planning out a project of this scope.
Like all novice scripters, up until now I’ve basically just written down a rough idea of what I want the end-product to do, and then dove straight into the code. It has worked out okay so far because the scripts I’ve been writing are fairly small, but when I was writing the Face Control Projection Tool I found myself going back and rewriting chunks of my code because I hadn’t planned it out.
So this time I’m doing things a little differently. I started off by writing down everything I could think of about how the tool looks, what it does, and how I can make it do it. At that stage having an organised document wasn’t important – the point was to just get everything down on paper. Previously that’s about as far as I ever went with planning.
The next step was to organise the mind spaghetti. My relatively organised notes are attached to this post and are what I’m working from for the most part. Note that for the purposes of this assignment I have kept some legacy information and I am commenting as I go to indicate changes to the plan.
Note also that metanodes are (albeit in a disorganised fashion) documented in the file, but I have since decided I won’t be able to get the metanode system working within the 4 week assignment period.
After getting my notes sorted it was time to jump into an IDE! I had set up a rough folder structure already to help me decide how to organise the above document, so in Eclipse (the IDE I am using) I pointed to that folder as my project and converted the .txt files I’d set up as placeholders into .py files. The folder structure has changed a little since then to make more sense and is below.
Note that I have included ui.py, face.py, and metanodes.py; I have done this as an indicator that they will be a part of the final product (of which this is a prototype), and so that I can visualise how they’ll fit in to the overall structure. Note also that I have not yet included __init__.py files for the subfolders.
So time to get working on the templates! I have discovered that a common practice when you are planning out a code is to write a template first. The template should declare all of the classes, methods, and functions that will be in the final code, and should have documentation for each. Most templates don’t actually have any working code, though – they call one another where appropriate but there’s no actual work being done. This is beneficial for a couple of reasons:
Firstly you really get to see how the code is gonna be laid out. You can see early on if you have the right classes/functions in the right files, and whether the way you’re structuring your classes is logical.
Secondly you can import and run the code, which is a really good way to check for syntax errors that could be a pain if you just jumped straight into code.
Thirdly, and probably most importantly, you get all of the logic straightened out ahead of time which means a lot less re-writing later on.
I’ve written a quick template for the Workbench and Bench classes.
The Workbench class sets and checks the application mode, so that when I implement this for more than just Maya it’ll know which implementation to use. It also holds the currently active Bench object.
The Bench class holds all the nodes you create as you build your rig. Every new node you instantiate will be sent to the active Bench object, as defined by Workbench.bench. This allows you to interactively build your rig with the Workbench tools, and then when you’re satisfied you can save out the rig as a bench script. When I add more application implementations, this will mean you can build a rig in one application and then save the bench out to build an identical rig in another application. For now, it means you can save it out in case you make changes to the skeleton (so you can just strip away the rig, change the skeleton, and load the bench to rebuild the rig) or if you have multiple similar skeletons, on which you want to build identical control rigs.
I’ve also made a start on the nodes.py classes. I’ve written the template for the Attribute class and Nodes class, which is the bulk of the work, at least when it comes to templates. I also got a little sidetracked making sure my idea of using the maya API would work for getting the node names and attributes interactively would work. I decided to do this to ensure that I never have stale references (i.e. you can change the node name or attributes in maya without the tool, and the tool will still have accurate information).
I found that I couldn’t just use the MSelectionList’s getDagPath method (and as a result I couldn’t use MFnDagNode(nodeDagPath) to get the dag object) for all nodes, because it doesn’t work for dependency nodes! Thankfully recently there have been a lot of people making resources for learning the maya API. I learned that for dependency nodes I need to use MSelectionList’s getDependNode method followed by MFnDependencyNode(dgNode) to get the equivalent object. Both that and the MFnDagNode have a name() method (for getting the current name) and a findPlug method for getting the attribute object. I found an awesome website with a ton of information about manupulating attributes through the API with that object, so I’ll be using that to flesh out my Attribute class when it comes time to actually write the main code.
So now I have the basis for my tool! I’m borrowing a few things from the way pymel works (other than having an Attribute class, simple things like node.isUniquelyNamed (which I also gave an alias nameIsUnique ’cause that makes more sense to me) and declaring some magic methods like __repr__ and __str__ to make the user experience a little more intuitive), but keep in mind that this is not meant to replace or copy pymel at all. It is intended (at least in its python form) to be a gateway through which rigs may be passed between applications and a tool to speed up the rigging process. I’m only packing nodes and commands as a necessity to make the bulk of the tool’s code application agnostic.
The rest of the week will be spent writing the rest of the template and double checking my organisational logic. I have a milestone on Friday to present all of my preproduction work (which in my mind includes the template), and then I’ll have three weeks to actually write the bulk of it.
Each week I have a sort of progress evaluation milestone. I intend to have the entirety of my conversion modules (commands.py and nodes.py) and some of the components written by the second milestone, and I want to have finished the components and have a lot of the modules written by the third.
Finally at the end of the four weeks I’ll have finished the modules and written the utilities (which I’ll be writing as I need them), as well as the basic functionality of the Bench class.