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…


The tricky bit is calling cmds.refresh() before connecting the new mesh, then calling it again before hooking it up as a collision object.

Here’s some code.

import maya.cmds as cmds
import maya.mel as mel
from sets import Set


def getShape(node):
    """
    Finds the shape node from a transform
    
    @param node: Object
    @type node: String
    
    @return: Shape node
    """
    
    if cmds.nodeType(node) == 'transform':
        shapes = [x for x in cmds.listRelatives(node, shapes=True, fullPath=True) if cmds.getAttr(x + '.intermediateObject') != True]
        if not shapes:
            raise RuntimeError, '%s has no shape' % node
        return shapes[0]
    elif cmds.nodeType(node) in ['mesh', 'nurbsCurve', 'nurbsSurface']:
        return node


def copyShaveToNewMesh(inMesh, newMesh):
    if cmds.objExists(inMesh) & cmds.objExists(newMesh):
        print 'copying from %s to %s' % (inMesh, newMesh)
        
        cmds.select(inMesh)
        
        
        inMeshShape = getShape(inMesh)
        newMeshShape = getShape(newMesh)
        shaveNodes = cmds.listConnections(inMeshShape, t='shaveHair' )
        
        # boil down the duplicates
        shaveNodes = list(Set(shaveNodes))

        for node in (shaveNodes or []):
            nodeShape = getShape(node)
            
            r = mel.eval('shaveCreateHairCopy %s' % (nodeShape))
            
            newShaveNodes = cmds.ls(sl=True)

            for newNode in (newShaveNodes or []):
                cmds.refresh()

                print newMeshShape + '.outMesh', newNode + '.inputMesh[0]'
                cmds.connectAttr(newMeshShape + '.outMesh', newNode + '.inputMesh[0]', force=True)
                cmds.refresh()
                cmds.connectAttr(newMeshShape + '.outMesh', newNode + '.collisionObjects[0]', force=True)
                    
        
    else:
        print 'either the souce or destination mesh cannot be found. borking'
        
        
sel = cmds.ls(sl=True)
if len(sel) >= 2:
    copyShaveToNewMesh(sel[0], sel[1])
else:
    print 'Select a source, then destination mesh'