Monday, October 31, 2011

Softbody solver: first test



This is an early test render from my slow-moving pet project, a softbody dynamics solver for Maya. It's based on the core technology from the hair solver I wrote for "Tron Legacy", with added support for conversion of arbitrary poly surfaces into tet meshes using TetGen.

I'm still working on extracting the resulting surface so that I can plug it into a proper renderer. Meanwhile, please enjoy the OpenGL framegrab above. It shows a tetrahedralized poly sphere which is affected by gravity and a couple of kinematic poly meshes which are represented as level sets internally (for faster and more robust collision lookups).

Due to the large amount of proprietary Digital Domain libraries involved in the solver, this is strictly an in-house project which will most likely never see the outside of DD's facilities. Hopefully I'll be able to use this to generate some interesting animation down the road though, even if it's just to satisfy my own curiousness.

The following credits are due:



Thursday, October 13, 2011

Maya 2012 idle event issue

This might be old news to some but I just discovered another baffling "feature" of Maya 2012. Try this in the Python editor of a Maya session you can do without:

import maya.utils
def foo():
  print 'here'
  maya.utils.processIdleEvents()
maya.utils.executeDeferred( 'foo()' )

Boom! Infinite recursion, stack blows up, segfault, good night.

So what's going on here? Well, it seems that somehow processIdleEvents() doesn't actually pop the event queue until after it's processed an event. Call me old fashioned but isn't that kinda backwards? Wouldn't you pop the queue right after you acquire the event, just to prevent issues like this?

The reason I came across this in the first place is we had a case of someone launching a Python script from MEL using evalDeferred, in order to avoid these massive UI deadlocks that would regularly happen due to some unfortunate combination of Maya 2009, Linux, pyQt and context menus. Now, deep down in one of our Python modules someone else had added a call to processIdleEvents() in order to guarantee that a loadPlugin() call has completed before proceeding - most probably due to some other synchronization issue in the Maya Python engine. You can guess what happened next, to everyone's stunned amazement: the script simply restarted, without any clue whatsoever why that might be.

The way I was able to catch this was by using 'traceback' to print out the call stack at a certain place in a module that I happened to have control over, realizing where the jump was happening. The solution? I'm not quite sure yet but it seems as though the UI deadlocks that gave rise to the use of evalDeferred in the first place have been mitigated post Maya 2009, so hopefully by just using a straight-up python() call instead we can put this behind us. However, this somewhat unorthodox treatment of idle events seems as something that should at least be mentioned in the API docs, if not fixed, period.

Or did I get any or all of this backwards? Please leave a comment if you have any thoughts on the matter!

Wednesday, October 12, 2011

Python list comprehension

I've written about Python list magic in the past and here's another tip:

Say you wanna create a list based on some other list, possibly filtering out certain entries and/or modifying the ones you choose to include.

Rather than this:

result = []
for item in mylist:
  if item > 5:
    result.append( '%05d'%item )

give this a go next time:

result = [ '%05d'%item for item in mylist if item>5 ]

Pretty neat, huh? Obviously this works on all valid sources of list data:

print 'Modules with \'site\' in the name:\n%s'%'\n'.join( \
      ['%s : %s'%(name,module) for name,module in \
        sys.modules.iteritems() if  'site' in name] )

Once we know this pattern it's fairly straightforward to create nested versions thereof, like this one straight out of a Maya script:

for attr in \
    [ '%s%s'%(attr,dim) for attr in ['t','r','s'] \ 
                         for dim in ['x','y','z'] ]:
  maya.cmds.connectAttr('%s.%s'%(sourceNode,attr), \
                        '%s.%s'%(targetNode,attr), f=True)

which combines two lists into one sequence of Maya attributes ['tx','ty','tz','rx','ry'... ] to connect between two nodes.

Expressive and neat, just the way I like it.