::more pymel speed findings::

July 19th, 2010 by hamish download the zooToolBox

I started poking the speed problems that plague pymel a bit more. It seems the problem may lie in the simple fact that instantiating MObject’s is expensive… try it out:

from maya.OpenMaya import *

import time
import maya.cmds as cmd

def asMObject( item ):
	sel = MSelectionList()
	sel.add( item )

	tmp = MObject()
	sel.getDependNode( 0, tmp )

	return tmp

def test():
	start = time.clock()
	for obj in cmd.ls():
		asMObject( obj )

	print 'time taken %0.3f' % (time.clock()-start)

This is pretty simple stuff. Simply iterating over all nodes in a blank scene and casting them to MObjects individually is slow. It takes 0.05 seconds on my machine on an empty scene. Doing the same thing with pymel takes about 0.21 seconds which is a little more than 4 times slower than this. Quite a leap from 350x.

So it seems Autodesk is largely to blame for some bloated script bindings.

From this little bit of investigation I’m not really convinced that its possible to have a fast unified abstraction of mel/api without help from Autodesk in cleaning up and speeding up their wrappers.

What might be interesting is looking into subclassing unicode and lazily populating the instance with api data as its requested from script to minimize the time spent instantiating maya’s object types. Incidentally pymel’s PyNode class used to inherit from unicode, but I’m unaware of how aggressive it was with lazy evaluation. I believe the reason Chad moved away from this idea in pymel was because strings in python are immutable and node names in maya are not. Having an immutable object represent mutable data is kinda sucky. But hey, we have to deal with this currently anyway, so its not like we’re moving backwards. Just not as far forward as we’d like.

The sucky thing about doing the lazy evaluation thing is that it’d be tricker to leverage inheritance – you wouldn’t want to determine the most appropriate class to cast the node as on instantiation because thats where it becomes expensive. So instead you’d have to dynamically populate the instance dictionary as functionality was requested.

Anyway… Once again we’re at the mercy of some shitty corner cutting from Autodesk.

In other news – has anyone seen how WELL blender has integrated scripting? Way better than any dcc app I’ve ever seen.

::no mo callable?!::

July 19th, 2010 by hamish download the zooToolBox

why did they remove callable( someObj ) in favor of hasattr( someObj, '__call__' )??? that’s horrible to write and to read! :(

ref: porting code to python 3

::more thoughts on pymel::

July 19th, 2010 by hamish download the zooToolBox

So after using pymel for a bunch I’m done with it.  Why you ask?

For starters its kinda this weird middle ground where its not mel (maya.cmds) and its not the api.  You can’t easily mix it with maya.cmds without having to throw in explicit str() casts all over your code, and to put isinstance( obj, PyNode ) checks everywhere which is messy and error prone.  You also can’t easily mix it with the api directly.

So you’re kinda left in this unusual grey zone.  PyNode objects do carry along with them some handles to API objects like their mobject and others depending on the PyNode in question, but again, you have to speckle you code with attribute references like someNode.__apiobject__ etc, if you want to call into anything inside maya.OpenMaya.

But most importantly, it is amazingly slow.  Like mind bogglingly slow when compared to mel. Exactly whats going on I haven’t spent the time to discover, but here is a very simple, albeit contrived demonstration of its tardiness.

import time
import maya.cmds as cmd
MAX = 1000
start = time.clock()
for n in xrange( MAX ):
	cmd.ls()
print 'time taken %0.3f' % (time.clock()-start)

from pymel.core import ls
start = time.clock()
for n in xrange( MAX ):
	ls()  #NOTE: this is using pymel’s wrapping of the ls command
print 'time taken %0.3f' % (time.clock()-start)

On my machine the first test which uses just mel takes 0.07 seconds on a completely empty scene. The second test, which uses pymel, takes a whopping 24 seconds.

That is a 350x speed difference. That’s HUGE!

Now, originally when I started writing this blog post I hadn’t done the speed tests. My assumption was that it was slower, but the slow down was probably merely a factor of 2 due to the way pymel has to cast return values from strings, back to MObjects. But I figured instead of writing the blog post with assumptions in it, I should at least do the work to get some actual numbers.

The question now becomes, do the benefits of pymel outweigh the negatives?  In my case I believe the answer is a resounding NO.

So after using it for as long as I have I’m kinda backpedaling. Its going to suck pulling pymel out of the tree, but clearly it has to be done. I’ve written a heap of rigging code using it, and have been wondering why it has been running so slow. My assumption was that it was my fault, and that somewhere I was writing some super redundant code. Now I know better.

This is a pretty big shame – I like what I gain from pymel, but I don’t like the constraints it puts on me, and the speed hit is unacceptable.

I do however, have some ideas on what might be a better solution to wrapping mel in a nicer way. It seems to me that extending the MObject class and making it really easy to cast strings to MObject instances would be a cool way to go. The wrapped objects would be native MObjects, so they’d be first class API citizens, and you could cast them to strings easily to pass back to mel should you need to. I’ve done some tests on the idea and so far it seems promising. I have a feeling I won’t ever have a solution as comprehensive as pymel, but at the same time I’m not sure thats what I want anyway.

Anyway, I just wanted to put my findings out there for anyone else who was shopping around for opinions on whether to use pymel or not. Consider yourself warned.

::holy shit modo sucks!::

June 6th, 2010 by hamish download the zooToolBox

Where to begin.

Actually, let me preface this with the statement that I’m talking as a technical artist, not a modeler. Modo is a pretty decent modeler, but as someone who has to shoehorn the thing into a production pipeline its probably one of the poorest applications I’ve ever encountered. Seriously.

Lets see, there is no documentation.  Their scripting syntax is just god awful bad.  Setting a value or performing an action via script is COMPLETELY DIFFERENT from querying data about the current state of what you’re just about to change.

An example here helps demonstrate – I want to query the name of something, so I use the command:

query scenesystem item.name <theItemId>

this will give me the name of the item “theItemId”.  To change the name of the item however, I need to use two commands like so:

select.subItem <theItemId> set mesh
item.name "holy shit modo sucks ballz!"

So not only is there absolutely no symmetry between querying and editing information in your scene, but there are these cryptic systems like sceneservice, renderservice, layerservice etc – none of which are documented, and good luck figuring out which service is responsible for what.

And holy wow how bad is authoring UI? Not only is it NOT POSSIBLE to script UI’s (so no dynamic UIs for you!), but its also a matter of hand editing xml files. And again – who the hell knows what any of the keys are for. But whats super awesome about this – if you get something “wrong” modo doesn’t give you errors, or warnings or anything helpful. It just does nothing. So you’re never quite sure what the hell is going on.

Incidentally, there is a “Form Editor” which will let you build buttons with macros in them. But thats it. Oh and there is no such thing as a checkbox widget either. Just a widget and if you give the widget a command which returns a bool then the widget magically knows to be a checkbox. And how do you define these variables you ask? Oh thats ALSO fun and ALSO involves hand editing xml files and hoping like a fancy pig that you divined the correct magics modo is expecting.

I could go on but honestly, what the hell is wrong with the people at luxology? They have clearly put a heap of thought into modo. As a modeler its quite a deep and sort of accessible tool, but what the fuck are they thinking about their scripting? Like not only is it bad, but its almost like its designed to be really bad. I find it hard to believe that someone honestly things any of the choices they’ve made are good.

Its even more baffling when you look at how RIGHT the blender guys have done it.

Whats your story luxology?

::more python love::

June 5th, 2010 by hamish download the zooToolBox

Man, I’m such a python fanboy…  Its such an enabling language.  And I say this as someone who is trying to be productive in c++ as well.  c++ is about as accessible as two inaccessible things nailed together.

Anyhoo, so whats with the lovin this time?  Well the other day I wanted to get a clear picture of what part of my python code base was being imported.  I was trying to make sure certain parts of my tools were pulling code only from a specific part of the tree in order to better isolate things.  Anyway I was kinda dreading the task, and figured it’d be a whole lot of no fun.  I had heard of import hooks, but knew nothing of them.

So 20 minutes later my problem was solved and I had a super convenient, generalized way of spewing all imports that were happening.  Furthermore it was a simple matter of running wing, setting a breakpoint in my import hook and bam.  The problem was solved in all of an hour, plus I have a convenient way of ensuring thing don’t creep in.  The import hook automatically turns itself on for me (or anyone else who sets the appropriate env var) so when I developing code I get a pretty rude warning if I start using code outside the desired part of the tree.

Sounds kinda weird – but the main point of it is we have a bunch python code which is shared across all projects studio-wide, and used mainly for tools like maya, modo, blender etc.  But we don’t want our project specific tools to rely on these pieces of code, otherwise people who aren’t content creators are no longer able to re-compile and optimize certain classes of assets.

Anyway, once again, python rocks.

::more use for trackableClassFactory::

April 6th, 2010 by hamish download the zooToolBox

This isn’t a critically useful use of the trackableClassFactory code I blogged about previously, but its kinda nice – and makes for less busywork when writing python plugins in maya.  Which of course means its less of a chore.

So basically what I do is I have a base class that implements some simple class methods like SyntaxCreator for the given class variable containing the syntax definition for the MPxCommand you’re writing.  This class also does things like auto hook up a “-h/-help” flag so that all commands defined in the plugin behave in the same way.

Then the initializePlugin function simply iterates over all subclasses of this base class, instantiates them and registers them as commands.  Similarly with the uninitializePlugin function.  So now to add a new command to the plugin you simply have to inherit from the base class and write your doIt method and describe the flags you want used.  The new command gets registered using the name you gave the class (although you *can* override this if you want) and everything just gets setup for you.

nice!  take that c++!

I’m sure this is possible in c++ but I’m pretty sure its going to be more than the 100 lines of code this solution requires.

::c++ is no fun::

April 5th, 2010 by hamish download the zooToolBox

wow, c++ is no fun to work with… admittedly I’m pretty n00b, so perhaps its just an unfamiliarity thing, but holy wow, there is a hell of a lot of busy work writing c++ code. everything takes like 10 times more typing.

here’s to hoping the pypy guys can make python mind numbingly fast.

::UI “Events” in maya::

March 10th, 2010 by hamish download the zooToolBox

I have a feeling UI programming in maya will actually not suck anywhere near as much with 2011 coming along soon.  I’m not 100% sure, but it sounds as though you’ll be able to use the scripted bindings for QT directly in maya for UI work in 2011.  If this is true – and I’m not sure it is – then things will certainly get a lot more exciting.  I’ve been restricted many times by maya’s lack of decent UI in the past, and integrating something like wxpython, while possible, is also a drag.

So anyway, this last week I was writing some UI to a tool that isn’t really finalized yet.  I want to keep the UI code flexible and modular so that its easy to change it up without creating a bunch of work.  Anyway if you’ve ever programmed UI using WX or QT there is this concept of events.  Basically pieces of UI can listen to events of a certain kind and define a function that gets called when that widget “hears” such an event.  Event driven UI’s are pretty common and make for a really powerful way of expressing action and reaction without having to make widgets aware of one another.  Because you’re not defining the relationship between widgets, doing things like radically changing up UI layouts is easier to achieve.

Anyway, so I wanted something like this in maya for my mel UIs.  So I made the simplest solution on the planet – which actually works out really well.  Basically I have a bunch of classes I wrote that wrap the maya mel UI widgets.  The base class has a sendEvent method and a process event method.  The sendEvent method basically just walks up the UI hierarchy and runs processEvent with the given event args.  And thats it.  Super simple, but it means I can write modular UI classes, and glue them together easily, or break off a piece of UI into a separate window etc.

Previously I’ve had to have child UI hold a handle to parent UI to call update functions or vice versa which makes this sort of modularization annoying at best, impossible at worst.  So anyway, super low tech simple solution – works a charm.  Anyone got a better idea?

::skinned geo in modo::

February 27th, 2010 by hamish download the zooToolBox

I’m not really a modo user – I’ve had to write a few scripts for it, but generally I’m considered a modo n00b.  But its quite a popular modeling app at work, which is hardly surprising given how much better it looks/sounds than maya for modeling.  So anyway, it occurred to me that I could use a modified version of the skin weight saving tool that I wrote for maya, as a way of creating skinning information for geometry out of modo.

How?

Well, we have a compilation step between export and visualization in the game engine.  This isn’t necessary, but it provides a convenient way of doing rigid error checking, and expensive optimization up front – and as of late we’ve been using it as a place to do additional assembly on the exported data.

When data gets exported out of the authoring app we try to preserve as much as the scene as possible – which is useful for a variety of reasons which I won’t go into here.  But for runtime efficiency, you generally want to do the opposite – rigorously remove anything that isn’t essential.  Some studios do this in their exporter, some studios do this at load time in the engine – we do it as a post export step before loading it in engine, which as I mentioned, provides a convenient place to do additional assembly on data that comes from multiple sources.

Getting back to the original point of the post – skinning geometry in modo.  Well, technically the skinning happens outside of modo, but all the data is authored inside modo, so it IS only a technicality.

First up – the skinning tool in maya is a point cloud loading and saving tool.  So basically you give it some skinned geometry, and the tool writes out position vectors with a list of joint names and joint weights – and thats it.  So if we can get that information authored in modo, then we can derive skinning data.

In modo what an artist would author is a hierarchy of transforms (I’m not sure if they’re called that in modo – modo isn’t that strong on clear terminology from what I’ve seen of it), and then parent a bunch of primitive geometry to those transforms.  The empty transforms get named in a special way (like bone_pelvis, or joint_arm_L etc) so the tool that derives the skinning data knows what to interpret as the skeleton, and then any geometry parented under that transform is assumed to be rigidly skinned to that joint.

So this is enough data to generate a point cloud that can be used to generate skinning information.  The skin weight tool then looks through the point cloud data, and does a radial search based on a couple of user settings for each vertex in the actual geometry to be skinned.  Generally what the search does is expand a starting radius until its found 2 or more verts.  Then it finds the closest verts *(see below for details on what this means), averages their weighting contribution and applies the skinning data.

So its kinda like sculpting volumes – and in fact, its a really fast and easy way of generating skinning information.

* The tool, to find the “closest verts” works kinda like this:  Given a vert on the actual geometry, it starts off with a radius of x.  The radius is grown each iteration until multiple verts are found.  From these verts, the closest is found.  The distance to this closest vert is stored, and the distances to all the other verts is then compared to a ratio.  Any vert that falls within the <closest distance>*<ratio> range is included in the weight sum (weighted by proximity).  By doing it this way scale isn’t important, and the user is presented with two fairly intuitive values to control the weighting.

::check it out – video tutorials!::

February 4th, 2010 by hamish download the zooToolBox

super cool – the rigging mentor dudes have made a video tutorial for zooPickwalk!  its way cool – way cooler than anything I would have ever done.  so head on over and check it out.