def getNodesCreatedBy( function, *args, **kwargs ): ''' returns a 2-tuple containing all the nodes created by the passed function, and the return value of said function NOTE: if any container nodes were created, their contents are omitted from the resulting node list - the container itself encapsulates them ''' newNodes, ret = apiExtensions.getNodesCreatedBy( function, *args, **kwargs ) #now remove nodes from all containers from the newNodes list newContainers = apiExtensions.filterByType( newNodes, apiExtensions.MFn.kSet ) #NOTE: nodes are MObject instances at this point newNodes = set( [ node for node in newNodes if node is not None ] ) for c in newContainers: for n in sets( c, q=True ) or []: if n in newNodes: newNodes.remove( n ) #containers contained by other containers don't need to be returned (as they're already contained by a parent) newTopLevelContainers = [] for c in newContainers: parentContainer = sets( c, q=True, parentContainer=True ) if parentContainer: continue newTopLevelContainers.append( c ) newNodes.add( c ) return newNodes, ret
def construct( self ): ''' builds the actual dynamic hair network ''' setNode = self._node objs = self.getObjs() #before we do anything, check to see whether the selected objects have any incoming connections warnAboutDisconnections = False for obj in objs: #check the object for incoming connections - if it has any, remove them for chan in ('t', 'r'): for ax in Axis.BASE_AXES: cons = listConnections( '%s.%s%s' % (obj, chan, ax), d=False ) if cons: warnAboutDisconnections = True if objectType( cons[0], isAType='animCurve' ): delete( cons[0] ) else: raise TypeError( "The object %s has non anim curve incoming connections - aborting! Please remove connections manually before proceeding" % obj ) if warnAboutDisconnections: printWarningStr( "Some of the objects had incoming connections (probably from animation). These connections have been broken! undo if you want them back" ) #wrap the creation of the nodes in a function - below this we execute this function via a wrapper which returns a list of new nodes created #this is done so we can easily capture the nodes created and store them in the set that describes this dynamic chain def doCreate(): positions = [] for obj in objs: positions.append( xform( obj, q=True, ws=True, rp=True ) ) #the objs may not be in the same hierarchy, so create a proxy chain that IS in a heirarchy proxyJoints = [] for obj in objs: select( cl=True ) j = createNode( 'joint' ) j = rename( j, '%s_dynChainProxy#' % obj.split( ':' )[-1].split( '|' )[-1] ) if proxyJoints: parent( j, proxyJoints[-1] ) delete( parentConstraint( obj, j ) ) proxyJoints.append( j ) #constrain the original to the proxy parentConstraint( j, obj ) #hook up the proxy root to a special message attribute so we can easily find the proxy chain again for things like baking etc... connectAttr( '%s.message' % proxyJoints[0], '%s.proxyRoot' % setNode ) #build a linear curve linearCurve = curve( d=1, p=positions ) linearCurveShape = listRelatives( linearCurve, s=True, pa=True )[0] select( linearCurve ) maya.mel.eval( 'makeCurvesDynamicHairs 1 0 1;' ) #find the dynamic curve shape cons = listConnections( '%s.worldSpace' % linearCurveShape, s=False ) if not cons: printWarningStr( "Cannot find follicle" ) return follicleShape = cons[0] cons = listConnections( '%s.outHair' % follicleShape, s=False ) if not cons: printWarningStr( "Cannot find hair system!" ) return hairSystemNode = cons[0] setAttr( '%s.startFrame' % hairSystemNode, playbackOptions( q=True, min=True ) ) cons = listConnections( '%s.outCurve' % follicleShape, s=False ) if not cons: printWarningStr( "Cannot find out curve!" ) return dynamicCurve = cons[0] dynamicCurveParent = listRelatives( dynamicCurve, p=True, pa=True ) #grab the dynamic curve's shape select( dynamicCurve ) maya.mel.eval( 'displayHairCurves "current" 1;' ) follicle = listRelatives( linearCurve, p=True, pa=True )[0] objParent = listRelatives( objs[0], p=True, pa=True ) if objParent: objParent = objParent[0] parent( follicle, objParent ) parent( proxyJoints[0], objParent ) setAttr( '%s.overrideDynamics' % follicle, 1 ) setAttr( '%s.pointLock' % follicle, 1 ) #hook up all the attributes connectAttr( '%s.stiffness' % setNode, '%s.stiffness' % follicle ) connectAttr( '%s.lengthFlex' % setNode, '%s.lengthFlex' % follicle ) connectAttr( '%s.damping' % setNode, '%s.damp' % follicle ) connectAttr( '%s.drag' % setNode, '%s.drag' % hairSystemNode ) connectAttr( '%s.friction' % setNode, '%s.friction' % hairSystemNode ) connectAttr( '%s.gravity' % setNode, '%s.gravity' % hairSystemNode ) connectAttr( '%s.turbStrength' % setNode, '%s.turbulenceStrength' % hairSystemNode ) connectAttr( '%s.turbFreq' % setNode, '%s.turbulenceFrequency' % hairSystemNode ) connectAttr( '%s.turbSpeed' % setNode, '%s.turbulenceSpeed' % hairSystemNode ) splineIkHandle = ikHandle( sj=proxyJoints[0], ee=proxyJoints[-1], curve=dynamicCurve, sol='ikSplineSolver', ccv=False )[0] #for some reason the dynamic curve gets re-parented by the ikHandle command (weird) so set the parent back to what it was originally parent( dynamicCurve, dynamicCurveParent ) newNodes, returnValue = getNodesCreatedBy( doCreate ) #stuff the nodes created into the set that describes this dynamic chain - just add transform nodes... for aNode in newNodes: if objectType( aNode, isAType='transform' ): sets( aNode, e=True, add=setNode )
def construct(self): ''' builds the actual dynamic hair network ''' setNode = self._node objs = self.getObjs() #before we do anything, check to see whether the selected objects have any incoming connections warnAboutDisconnections = False for obj in objs: #check the object for incoming connections - if it has any, remove them for chan in ('t', 'r'): for ax in Axis.BASE_AXES: cons = listConnections('%s.%s%s' % (obj, chan, ax), d=False) if cons: warnAboutDisconnections = True if objectType(cons[0], isAType='animCurve'): delete(cons[0]) else: raise TypeError( "The object %s has non anim curve incoming connections - aborting! Please remove connections manually before proceeding" % obj) if warnAboutDisconnections: printWarningStr( "Some of the objects had incoming connections (probably from animation). These connections have been broken! undo if you want them back" ) #wrap the creation of the nodes in a function - below this we execute this function via a wrapper which returns a list of new nodes created #this is done so we can easily capture the nodes created and store them in the set that describes this dynamic chain def doCreate(): positions = [] for obj in objs: positions.append(xform(obj, q=True, ws=True, rp=True)) #the objs may not be in the same hierarchy, so create a proxy chain that IS in a heirarchy proxyJoints = [] for obj in objs: select(cl=True) j = createNode('joint') j = rename( j, '%s_dynChainProxy#' % obj.split(':')[-1].split('|')[-1]) if proxyJoints: parent(j, proxyJoints[-1]) delete(parentConstraint(obj, j)) proxyJoints.append(j) #constrain the original to the proxy parentConstraint(j, obj) #hook up the proxy root to a special message attribute so we can easily find the proxy chain again for things like baking etc... connectAttr('%s.message' % proxyJoints[0], '%s.proxyRoot' % setNode) #build a linear curve linearCurve = curve(d=1, p=positions) linearCurveShape = listRelatives(linearCurve, s=True, pa=True)[0] select(linearCurve) maya.mel.eval('makeCurvesDynamicHairs 1 0 1;') #find the dynamic curve shape cons = listConnections('%s.worldSpace' % linearCurveShape, s=False) if not cons: printWarningStr("Cannot find follicle") return follicleShape = cons[0] cons = listConnections('%s.outHair' % follicleShape, s=False) if not cons: printWarningStr("Cannot find hair system!") return hairSystemNode = cons[0] setAttr('%s.startFrame' % hairSystemNode, playbackOptions(q=True, min=True)) cons = listConnections('%s.outCurve' % follicleShape, s=False) if not cons: printWarningStr("Cannot find out curve!") return dynamicCurve = cons[0] dynamicCurveParent = listRelatives( dynamicCurve, p=True, pa=True) #grab the dynamic curve's shape select(dynamicCurve) maya.mel.eval('displayHairCurves "current" 1;') follicle = listRelatives(linearCurve, p=True, pa=True)[0] objParent = listRelatives(objs[0], p=True, pa=True) if objParent: objParent = objParent[0] parent(follicle, objParent) parent(proxyJoints[0], objParent) setAttr('%s.overrideDynamics' % follicle, 1) setAttr('%s.pointLock' % follicle, 1) #hook up all the attributes connectAttr('%s.stiffness' % setNode, '%s.stiffness' % follicle) connectAttr('%s.lengthFlex' % setNode, '%s.lengthFlex' % follicle) connectAttr('%s.damping' % setNode, '%s.damp' % follicle) connectAttr('%s.drag' % setNode, '%s.drag' % hairSystemNode) connectAttr('%s.friction' % setNode, '%s.friction' % hairSystemNode) connectAttr('%s.gravity' % setNode, '%s.gravity' % hairSystemNode) connectAttr('%s.turbStrength' % setNode, '%s.turbulenceStrength' % hairSystemNode) connectAttr('%s.turbFreq' % setNode, '%s.turbulenceFrequency' % hairSystemNode) connectAttr('%s.turbSpeed' % setNode, '%s.turbulenceSpeed' % hairSystemNode) splineIkHandle = ikHandle(sj=proxyJoints[0], ee=proxyJoints[-1], curve=dynamicCurve, sol='ikSplineSolver', ccv=False)[0] #for some reason the dynamic curve gets re-parented by the ikHandle command (weird) so set the parent back to what it was originally parent(dynamicCurve, dynamicCurveParent) newNodes, returnValue = getNodesCreatedBy(doCreate) #stuff the nodes created into the set that describes this dynamic chain - just add transform nodes... for aNode in newNodes: if objectType(aNode, isAType='transform'): sets(aNode, e=True, add=setNode)