Duplicating Shave setups

Shave and a Haircut… interesting bit of kit.

I’ve been needing to duplicate hair setups onto meshes that aren’t world aligned (they have different animation caches on them, otherwise the same mesh), which means that Shave’s built in duplicating tools won’t necessarily work. For some reason, trying to script the duplication and plugging in a new mesh wasn’t working, until i decided to call a scene refresh. That fixed it! The old refresh trick…

Read more

Pose driver

In rigging land, and I’m making a rotation driver from built-in maya nodes. This usually drives some front of chain blendshapes (use Chad Vernon’s awesome cvShapeInverter tool) to do corrective blends. This is similar in concept to the Comet poseDeformer.
Read more

Maya QT windows – inaccessible titlebars

The very first time you call a QT interface window (in a given user preferences set), it will draw the window so that the titlebar is offscreen. Problematic, because you can’t move the window, and it tends to freak your users out.

This is because Maya doesn’t have a window pref for it yet, and it’s default is brain meltingly stupid. Mac maya doesn’t suffer from this problem. Not sure about Linux.

So, use this function after you showWindow(). For example:

uiFile = "/path/to/uiFile.ui"
rlDialog = cmds.loadUI(f=uiFile)
cmds.showWindow(rlDialog)
windowPosFix(rlDialog)

def windowPosFix(windowName):
    """
    Fix for QT windows with no position information. If they are positioned at the very
    top left of screen, they are moved somewhere more sensible.
    
    @param windowName: Window Name
    @type windowName: String
    """
    
    if cmds.window(windowName, query=True, exists=True):
        winPos = cmds.window(windowName, query=True, topLeftCorner=True)
        if winPos[0] <=0 or winPos[1] <=0:
            cmds.window(windowName, edit=True, topLeftCorner=[150,150])

Maya QT interfaces in a class

Most tutorials online have suggested the way to fire commands inside QT interfaces launched in Maya (via cmds.loadUi – not involving pyQT) is to add a string property like:

+command="myPythonInstance.pythonCommand()"

Pretty craptastical – it can only fire commands inside a specific python module, the name of which has to be known when you’re laying out your interface.

Ideally, we’d like to have our interface instanced from a python class. This would allow us, amongst other things, so have multiple, independant instances. However it seems that a “self” reference can’t get passed to an interface, which is what you’d reallly like to do.

+command=self.pythonCommand

A (reasonably hacky) solution is to create the widget callbacks from inside our python class, after we’ve loaded the interface via cmds.loadUi().

import maya.cmds as cmds

class myUi(object):
	def __init__(self, *args):
		uiFile = '/path/to/uiFile.ui'
		rlDialog = cmds.loadUI(f=uiFile)
		cmds.showWindow(rlDialog)
		cmds.button( "ovrAdd_btn", edit=True, command=self.overrideAdd )

	def overrideAdd(self, *args):
		print 'do something!'

Which is slightly better, but we’re still referring to our widget by a string name. This is problematic if you have multiple instances of this class – targeting “ovrAdd_btn” is going to get confusing. We need to find out exactly which control, in amongst the whole widget mess, is the one that we’ve spawned when we’re called cmds.loadUI().

Sadly, loadUI() doesn’t give us any help in this department. So, and here’s the hacky bit, we can trawl through the widgets to find those belonging to our class instance, store them in a dict and then we can refer back to them by a simplified name. Easy!

import maya.cmds as cmds

def widgetPath(windowName, widgetNames):
    """
    
    @param windowName: Window instance name to search
    @param widgetNames: list of names to search for
    """
    
    returnDict = {}
    mayaWidgetList = cmds.lsUI(dumpWidgets=True)
    
    for widget in widgetNames:
        for mayaWidge in mayaWidgetList:
            if windowName in mayaWidge:
                if mayaWidge.endswith(widget):
                    returnDict[widget] = mayaWidge
                    
    return returnDict

class myUi(object):
	def __init__(self, *args):
		uiWidgetList = ['ovrAdd_btn']

		uiFile = '/path/to/uiFile.ui'
		rlDialog = cmds.loadUI(f=uiFile)
		self.uiObjects = widgetPath(rlDialog, uiWidgetList)
		
		cmds.showWindow(rlDialog)
		
		cmds.button( self.uiObjects["ovrAdd_btn"], edit=True, command=self.overrideAdd )

	def overrideAdd(self, *args):
		print 'do something!'

Trawling through Maya’s widget list isn’t particularly elegant, but you only have to do it once per class initialisation, so there isn’t too much of a cost. The advantage is that you can now have per-instance widget names.

Why not just use pyQT proper, you ask? Installing external dependencies isn’t always an option for our less techy brethren, or easily done in a studio-wide fashion. Using pyQT would be far better (and give all sorts of other benefits), but if you’re constrained to using vanilla maya / python, this seems to do the trick.

Name changed callbacks in maya/python/api

Could not figure this out for quite a while – maya API is a little obtuse if you’re not used to it, and with all the examples in c++, you’re on your own when it comes to translating to python. Ergh.

 

from maya import OpenMaya

def nameChangedCallback( *args):
    node = args[0]
    # convert the MObject to a dep node
    depNode = OpenMaya.MFnDependencyNode(node)
    oldName = args[1]

    print '----\nNameChangedCallback'
    print 'newName: ', depNode.name()
    print 'oldName', oldName
    print 'type', depNode.typeName()

    

# passing in a null MObject (ie, without a name as an argument)
# registers the callback to get all name changes in the scene
# if you wanted to monitor a specific object's name changes
# you could pass a name to the MObject

nullMObject = OpenMaya.MObject()
OpenMaya.MNodeMessage.addNameChangedCallback( nullMObject, nameChangedCallback )

 

EXR compression in maya

If you want to script it, it’s here:
setAttr “mentalrayGlobals.imageCompression” 4

South for db migrations

South is looking like a godsend for Django database migrations… so far, so sexy.

Maya python snippets

Posting these for my (and anybody else’s) edification – the help docs only get you so far, especially when the nitty gritty of actually *doing* something is more complicated.

Get current shelf:

import maya.cmds as cmds
import maya.mel as mel

gShelfTopLevel = mel.eval('$temp1=$gShelfTopLevel')
print cmds.tabLayout(gShelfTopLevel, query=True, st=True)

Install a menu in the main window menubar:

import maya.cmds as cmds
import maya.mel as mel

gMainWindow = maya.mel.eval('$temp1=$gMainWindow')
oMenu= cmds.menu(parent=gMainWindow, tearOff = True, label = 'MyLabel')
subMenu= cmds.menuItem(parent=oMenu, label='mySubMenu', subMenu=True)
cmds.menuItem(parent=subMenu, label='MenuItem1', c='somePythonProc()')

Interfaces
This is quite handy.

Showreel Updates

New showreels posted! Yes, I have been doing stuff.

Character Animation Showreel

Download movie: chrisg_animationReel_2010

TVC Showreel

Download movie: chrisg_generalistReel_2010

cgBreakdown v1.33

A small update to cgBreakdown. Will now update params on refmodels, which tend to report themselves as locked. Thanks to Alex Kong for the heads up.

Return top