Beispiel #1
0
	def on_filterChanged( self, *args ):
		self.UI_files.setFilter( self.UI_filter.getValue() )
		if self._filterChangeCB:
			try:
				self._filterChangeCB()
			except:
				printWarningStr( "The filter change callback %s failed!" % self._filterChangeCB )
Beispiel #2
0
def switchAnimationToFk(control,
                        handle=None,
                        attrName='ikBlend',
                        onValue=1,
                        offValue=0,
                        key=True,
                        startFrame=None,
                        endFrame=None):

    #grab the key times for keys set on the t or r channels on the ik control - these are the frames we want to switch to fk on
    keyTimes = keyframe(control, q=True, at=('t', 'r'), tc=True)
    if not keyTimes:
        switchToFk(control, handle, attrName, offValue, key)
        printWarningStr("No keys found on the ik control - nothing to do!")
        return

    #remove duplicate key times and sort them
    keyTimes = removeDupes(keyTimes)
    keyTimes.sort()
    cropValues(keyTimes, startFrame, endFrame)

    joints = getJointsFromIkHandle(handle)
    for time in keyTimes:
        currentTime(time, e=True)
        switchToFk(control, handle, attrName, onValue, offValue, key, joints)

    select(joints[-1])
Beispiel #3
0
def switchToFk( control, handle=None, attrName='ikBlend', onValue=1, offValue=0, key=False, joints=None ):
	if handle is None:
		handle = control

	if handle is None or not objExists( handle ):
		printWarningStr( "no ikHandle specified" )
		return

	#if we weren't passed in joints - discover them now
	if joints is None:
		joints = getJointsFromIkHandle( handle )

	#make sure ik is on before querying rotations
	setAttr( '%s.%s' % (control, attrName), onValue )
	rots = []
	for j in joints:
		rot = getAttr( "%s.r" % j )[0]
		rots.append( rot )

	#now turn ik off and set rotations for the joints
	setAttr( '%s.%s' % (control, attrName), offValue )
	for j, rot in zip( joints, rots ):
		for ax, r in zip( ('x', 'y', 'z'), rot ):
			if getAttr( '%s.r%s' % (j, ax), se=True ):
				setAttr( '%s.r%s' % (j, ax), r )

	alignFast( joints[2], handle )
	if key:
		setKeyframe( joints )
		setKeyframe( '%s.%s' % (control, attrName) )
Beispiel #4
0
def switchAnimationToIk( control, poleControl=None, handle=None, attrName='ikBlend', onValue=1, key=True, startFrame=None, endFrame=None ):

	#get the joints the ik control drives - we need these to get keyframes from so we know which frames to trace the ik control on
	joints = getJointsFromIkHandle( handle )
	if not joints:
		printWarningStr( "Cannot find the fk controls for the given ik control" )
		return

	#grab the key times for keys set on the t or r channels on the ik control - these are the frames we want to switch to fk on
	keyTimes = keyframe( joints, q=True, at=('t', 'r'), tc=True )
	if not keyTimes:
		switchToIk( ikControl, poleControl, handle, attrName, onValue, key )
		printWarningStr( "No keys found on the fk controls - nothing to do!" )
		return

	#remove duplicate key times and sort them
	keyTimes = removeDupes( keyTimes )
	keyTimes.sort()
	cropValues( keyTimes, startFrame, endFrame )

	#clear out the keys for the ik control
	cutKey( control, poleControl, t=(keyTimes[0], keyTimes[-1]), cl=True )

	startFrame = keyTimes[0]
	currentTime( startFrame, e=True )
	setKeyframe( control, poleControl, t=(startFrame,) )

	for time in keyTimes:
		currentTime( time, e=True )
		switchToIk( control, poleControl, handle, attrName, onValue, key, joints, _isBatchMode=True )

	setKeyframe( control, t=keyTimes, at=attrName, v=onValue )

	select( control )
Beispiel #5
0
def getControlsFromObjs( control ):
	'''
	attempts to retrieve the pole vector control, the ik handle and all fk controls given an ik rig control.  The
	information is returned in a 3 tuple containing:

	ikHandle, poleControl, fkControls
	'''
	errorValue = None, None, None, None

	try:
		part = rigPrimitives.RigPart.InitFromItem( control )

		return part.getControl( 'control' ), part.getIkHandle(), part.getControl( 'poleControl' ), part.getFkControls()
	except rigPrimitives.RigPartError: pass

	#so if the control we've been given isn't a rig primitive, lets try to extract whatever information we can from right click commands - if any exist
	trigger = Trigger( ikControl )
	switchCmdStr = None
	for n, cmdName, cmdStr in trigger.iterMenus():
		if cmdName.lower() == _IK_CMD_NAME:
			switchCmdStr = trigger.resolve( cmdStr )
			break

	if switchCmdStr is None:
		printWarningStr( "Cannot find the %s command - aborting!" % _IK_CMD_NAME )
		return errorValue

	#extract the control handle from the switch command - it may or may not exist, depending on which
	rexStr = re.compile( '-ikHandle \%([a-ZA-Z0-9_:|]+)', re.IGNORECASE | re.MULTILINE )
	match = rexStr.search( switchCmdStr )
	if not match:
		if match.groups()[0]:
			control = match.groups()[0]

	#extract the ik handle from the switch command
	rexStr = re.compile( '-ikHandle \%([a-ZA-Z0-9_:|]+)', re.IGNORECASE | re.MULTILINE )
	match = rexStr.search( switchCmdStr )
	if not match:
		printWarningStr( "Could not determine the ik handle from the given control" )
		return errorValue

	handle = match.groups()[0]
	if handle is None:
		printWarningStr( "Could not find the ik handle at the given connect index!" )
		return errorValue

	#now extract the pole control from the switch command
	rexStr = re.compile( '-pole \%([a-ZA-Z0-9_:|]+)', re.IGNORECASE | re.MULTILINE )
	match = rexStr.search( switchCmdStr )
	if not match:
		printWarningStr( "Could not determine the pole vector control from the given control" )
		return errorValue

	poleControl = match.groups()[0]
	if poleControl is None:
		printWarningStr( "Could not find the ik handle at the given connect index!" )
		return errorValue

	return control, poleControl, handle, getJointsFromIkHandle( handle )
Beispiel #6
0
def changeParent( parent=0, objs=None ):
	if objs is None:
		objs = ls( sl=True, type='transform' ) or []

	#only bother with objects that have a "parent" attribute and whose parent attribute value is not the same as the one we've been passed
	objsToActOn = []
	for obj in objs:
		if objExists( '%s.parent' % obj ):
			objsToActOn.append( obj )

	objs = objsToActOn

	#if there are no objects, bail
	if not objs:
		printWarningStr( "There are no objects to work on - aborting!" )
		return

	#store the initial time so we can restore it at the end
	initialTime = currentTime( q=True )

	#first we need to make sure that any frame with a rotation key needs to have a key on ALL rotation axes - so make this happen
	keyTimes = keyframe( objs, q=True, at=('t', 'r'), tc=True )
	if not keyTimes:
		printWarningStr( "No keys found on the objects - nothing to do!" )
		return

	#remove duplicate key times and sort them
	keyTimes = removeDupes( keyTimes )
	keyTimes.sort()

	#store the objects that each have keys at each key time in a dict so we don't have to query maya again. maya queries are slower than accessing python data structures
	timeObjs = {}
	for time in keyTimes:
		currentTime( time, e=True )
		timeObjs[ time ] = objsWithKeysAtThisTime = []
		for obj in objs:
			keyOnCurrentTime = keyframe( obj, q=True, t=(time,), at=('parent', 't', 'r'), kc=True )
			if keyOnCurrentTime:
				setKeyframe( obj, at=('parent', 't', 'r') )
				objsWithKeysAtThisTime.append( obj )

	#now that we've secured the translation/rotation poses with keys on all axes, change the parent on each keyframe
	for time, objsWithKeysAtThisTime in timeObjs.iteritems():
		currentTime( time, e=True )
		for obj in objsWithKeysAtThisTime:
			pos = xform( obj, q=True, rp=True, ws=True )
			rot = xform( obj, q=True, ro=True, ws=True )

			#change the parent and move/rotate back to the original world space pose
			setAttr( '%s.parent' % obj, parent )

			move( pos[0], pos[1], pos[2], obj, ws=True, rpr=True )
			rotate( rot[0], rot[1], rot[2], obj, ws=True )

			#lock in the pose
			setKeyframe( obj, at=('parent', 't', 'r') )

	#finally restore the initial time
	currentTime( initialTime, e=True )
Beispiel #7
0
 def on_filterChanged(self, *args):
     self.UI_files.setFilter(self.UI_filter.getValue())
     if self._filterChangeCB:
         try:
             self._filterChangeCB()
         except:
             printWarningStr("The filter change callback %s failed!" %
                             self._filterChangeCB)
Beispiel #8
0
def getJointsFromIkHandle(handle):

    #get the joints the ik control drives - we need these to get keyframes from so we know which frames to trace the ik control on
    joints = ikHandle(handle, q=True, jl=True)
    effector = ikHandle(handle, q=True, ee=True)
    cons = listConnections('%s.tx' % effector, d=False)
    if not cons:
        printWarningStr("Could not find the end effector control!")
        return

    joints.append(cons[0])

    return joints
Beispiel #9
0
def getJointsFromIkHandle( handle ):

	#get the joints the ik control drives - we need these to get keyframes from so we know which frames to trace the ik control on
	joints = ikHandle( handle, q=True, jl=True )
	effector = ikHandle( handle, q=True, ee=True )
	cons = listConnections( '%s.tx' % effector, d=False )
	if not cons:
		printWarningStr( "Could not find the end effector control!" )
		return

	joints.append( cons[0] )

	return joints
Beispiel #10
0
def propagateWeightChangesToModel_confirm():
	'''
	simply wraps the propagateWeightChangesToModel function with a confirmation dialog
	'''
	allMeshNodes = ls( type='mesh' )
	allSkinnedMeshes = [ mesh for mesh in allMeshNodes if mel.findRelatedSkinCluster( mesh ) ]
	if not allSkinnedMeshes:
		printWarningStr( "No skinned meshes can be found in the scene!  Aborting!" )
		return

	BUTTONS = OK, CANCEL = 'Ok', 'Cancel'
	ret = confirmDialog( m='Are you sure you want to push skinning changes to the model?', t='Are you sure?', b=BUTTONS, db=CANCEL )
	if ret == OK:
		propagateWeightChangesToModel( allSkinnedMeshes )
Beispiel #11
0
def switchAnimationToIk(control,
                        poleControl=None,
                        handle=None,
                        attrName='ikBlend',
                        onValue=1,
                        key=True,
                        startFrame=None,
                        endFrame=None):

    #get the joints the ik control drives - we need these to get keyframes from so we know which frames to trace the ik control on
    joints = getJointsFromIkHandle(handle)
    if not joints:
        printWarningStr("Cannot find the fk controls for the given ik control")
        return

    #grab the key times for keys set on the t or r channels on the ik control - these are the frames we want to switch to fk on
    keyTimes = keyframe(joints, q=True, at=('t', 'r'), tc=True)
    if not keyTimes:
        switchToIk(ikControl, poleControl, handle, attrName, onValue, key)
        printWarningStr("No keys found on the fk controls - nothing to do!")
        return

    #remove duplicate key times and sort them
    keyTimes = removeDupes(keyTimes)
    keyTimes.sort()
    cropValues(keyTimes, startFrame, endFrame)

    #clear out the keys for the ik control
    cutKey(control, poleControl, t=(keyTimes[0], keyTimes[-1]), cl=True)

    startFrame = keyTimes[0]
    currentTime(startFrame, e=True)
    setKeyframe(control, poleControl, t=(startFrame, ))

    for time in keyTimes:
        currentTime(time, e=True)
        switchToIk(control,
                   poleControl,
                   handle,
                   attrName,
                   onValue,
                   key,
                   joints,
                   _isBatchMode=True)

    setKeyframe(control, t=keyTimes, at=attrName, v=onValue)

    select(control)
Beispiel #12
0
    def apply(self, nodes, attributes=None, **kwargs):
        self.load()

        # do a version check - if older version clip is being used - perhaps we can write conversion functionality?
        try:
            if self._so.version != VER:
                printWarningStr("the anim clip version being loaded is old.  YMMV!")
        except KeyError:
            printErrorStr("this is an old VER 1 pose clip - I don't know how to load them anymore...")
            return

            # generate the name mapping
        slamApply = kwargs.pop("slam", False)
        if slamApply:
            mapping = mappingUtils.matchNames(cmd.ls(typ="transform"), nodes)
        else:
            mapping = mappingUtils.matchNames(self._nodes, nodes)

        self._clip.applyToNodes(nodes)
Beispiel #13
0
	def apply( self, nodes, attributes=None, **kwargs ):
		self.load()

		#do a version check - if older version clip is being used - perhaps we can write conversion functionality?
		try:
			if self._so.version != VER:
				printWarningStr( "the anim clip version being loaded is old.  YMMV!" )
		except KeyError:
			printErrorStr( "this is an old VER 1 pose clip - I don't know how to load them anymore..." )
			return

		#generate the name mapping
		slamApply = kwargs.pop( 'slam', False )
		if slamApply:
			mapping = mappingUtils.matchNames( cmd.ls( typ='transform' ), nodes )
		else:
			mapping = mappingUtils.matchNames( self._nodes, nodes )

		self._clip.applyToNodes( nodes )
Beispiel #14
0
def switchAnimationToFk( control, handle=None, attrName='ikBlend', onValue=1, offValue=0, key=True, startFrame=None, endFrame=None ):

	#grab the key times for keys set on the t or r channels on the ik control - these are the frames we want to switch to fk on
	keyTimes = keyframe( control, q=True, at=('t', 'r'), tc=True )
	if not keyTimes:
		switchToFk( control, handle, attrName, offValue, key )
		printWarningStr( "No keys found on the ik control - nothing to do!" )
		return

	#remove duplicate key times and sort them
	keyTimes = removeDupes( keyTimes )
	keyTimes.sort()
	cropValues( keyTimes, startFrame, endFrame )

	joints = getJointsFromIkHandle( handle )
	for time in keyTimes:
		currentTime( time, e=True )
		switchToFk( control, handle, attrName, onValue, offValue, key, joints )

	select( joints[-1] )
Beispiel #15
0
	def __init__( self, partContainer, skeletonPart=None ):
		if partContainer is not None:
			assert isRigPartContainer( partContainer ), "Must pass a valid rig part container! (received %s - a %s)" % (partContainer, nodeType( partContainer ))

		self._container = partContainer
		self._skeletonPart = skeletonPart
		self._worldPart = None
		self._worldControl = None
		self._partsNode = None
		self._qss = None
		self._idx = None

		if partContainer:
			if skeletonPart is None:
				try:
					self.getSkeletonPart()

				#this isn't fatal, although its not good
				except RigPartError, x:
					printWarningStr( str( x ) )
Beispiel #16
0
def propagateWeightChangesToModel_confirm():
    '''
	simply wraps the propagateWeightChangesToModel function with a confirmation dialog
	'''
    allMeshNodes = ls(type='mesh')
    allSkinnedMeshes = [
        mesh for mesh in allMeshNodes if mel.findRelatedSkinCluster(mesh)
    ]
    if not allSkinnedMeshes:
        printWarningStr(
            "No skinned meshes can be found in the scene!  Aborting!")
        return

    BUTTONS = OK, CANCEL = 'Ok', 'Cancel'
    ret = confirmDialog(
        m='Are you sure you want to push skinning changes to the model?',
        t='Are you sure?',
        b=BUTTONS,
        db=CANCEL)
    if ret == OK:
        propagateWeightChangesToModel(allSkinnedMeshes)
Beispiel #17
0
    def __call__(self):
        if not self.ENABLED:
            return

        #if autokey is turned on, bail - this + autokey = potentially weird behaviour
        #NOTE: the tool will turn autokey off automatically when loaded - so if its on, its because the user has turned it back on.  Also
        #worth noting - this tool will restore the initial autokey state when closed/turned off...
        if autoKeyframe(q=True):
            printWarningStr(
                "Autokey is enabled - This tool doesn't play nice with autokey!  Please turn it off!"
            )
            return

        #if there are no entries in here - bail, they've already been handled
        if not PRE_ATTR_VALUES:
            return

        #put the following into a single undo chunk
        try:
            undoInfo(openChunk=True)
            for attrpath, preValue in PRE_ATTR_VALUES.iteritems():
                curValue = getAttr(attrpath)
                valueDelta = curValue - preValue

                #if there was no delta, keep loopin
                if not valueDelta:
                    continue

                #if there are no keyframes on this attribute - keep loopin
                if not keyframe(attrpath, q=True, kc=True):
                    continue

                keyframe(attrpath, e=True, t=(), vc=valueDelta, relative=True)

            PRE_ATTR_VALUES.clear()
        finally:
            undoInfo(closeChunk=True)

        #setup an idle event to re-populate the PRE_ATTR_VALUES dict when everything has finished processing
        scriptJob(runOnce=True, idleEvent=self.ui.on_selectionChange)
Beispiel #18
0
def changeRo( objs=None, ro=XYZ ):
	if ro not in ROT_ORDER_STRS:
		raise TypeError( "need to specify a valid rotation order - one of: %s" % ' '.join( ROT_ORDER_STRS ) )

	if objs is None:
		objs = ls( sl=True, type='transform' )

	roIdx = list( ROT_ORDER_STRS ).index( ro )

	#filter out objects that don't have all 3 rotation axes settable and while we're at it store the rotation orders for each object
	#in a dict - since accessing a python dict is WAY faster than doing a getAttr for each frame in the loop below
	RO_DICT = {}
	objsWithAllChannelsSettable = []

	for obj in objs:
		if not getAttr( '%s.r' % obj, se=True ):
			printWarningStr( "Not all rotation axes on the object %s are settable - skipping!" % obj )
			continue

		objRo = getAttr( '%s.ro' % obj )

		#if the rotation order of this object is the same as what we're changing it to - skip the object entirely
		if objRo == roIdx:
			printWarningStr( "The object %s already has the rotation order %s - skipping!" % (obj, ro) )
			continue

		RO_DICT[ obj ] = objRo
		objsWithAllChannelsSettable.append( obj )

	#early out if we have no objects to work on
	objs = objsWithAllChannelsSettable
	if not objs:
		printWarningStr( "No objects to act on - exiting" )
		return

	#cache the conversion method
	convertToMethod = MATRIX_ROTATION_ORDER_CONVERSIONS_TO[ roIdx ]

	#construct a key server object to march over keys and objects
	keyServer = KeyServer( objs, True )
	for time in keyServer:
		for obj in keyServer.getNodesAtTime():
			setKeyframe( obj, at='r' )

	#now that we're secured the rotation poses with keys on all axes, fix up each rotation value to use the desired rotation order
	for time in keyServer:
		for obj in keyServer.getNodesAtTime():
			currentRoIdx = RO_DICT[ obj ]

			rot = getAttr( '%s.r' % obj )[0]
			rotMatrix = MATRIX_ROTATION_ORDER_CONVERSIONS_FROM[ currentRoIdx ]( degrees=True, *rot )

			newRot = convertToMethod( rotMatrix, True )
			setAttr( '%s.r' % obj, *newRot )
			setKeyframe( obj, at='r' )

	#now change the rotation order to what it should be
	for obj in objs:
		setAttr( '%s.ro' % obj, roIdx )
Beispiel #19
0
	def __call__( self ):
		if not self.ENABLED:
			return

		#if autokey is turned on, bail - this + autokey = potentially weird behaviour
		#NOTE: the tool will turn autokey off automatically when loaded - so if its on, its because the user has turned it back on.  Also
		#worth noting - this tool will restore the initial autokey state when closed/turned off...
		if autoKeyframe( q=True ):
			printWarningStr( "Autokey is enabled - This tool doesn't play nice with autokey!  Please turn it off!" )
			return

		#if there are no entries in here - bail, they've already been handled
		if not PRE_ATTR_VALUES:
			return

		#put the following into a single undo chunk
		try:
			undoInfo( openChunk=True )
			for attrpath, preValue in PRE_ATTR_VALUES.iteritems():
				curValue = getAttr( attrpath )
				valueDelta = curValue - preValue

				#if there was no delta, keep loopin
				if not valueDelta:
					continue

				#if there are no keyframes on this attribute - keep loopin
				if not keyframe( attrpath, q=True, kc=True ):
					continue

				keyframe( attrpath, e=True, t=(), vc=valueDelta, relative=True )

			PRE_ATTR_VALUES.clear()
		finally:
			undoInfo( closeChunk=True )

		#setup an idle event to re-populate the PRE_ATTR_VALUES dict when everything has finished processing
		scriptJob( runOnce=True, idleEvent=self.ui.on_selectionChange )
Beispiel #20
0
def switchToIk(control,
               poleControl=None,
               handle=None,
               attrName='ikBlend',
               onValue=1,
               key=False,
               joints=None,
               _isBatchMode=False):
    if handle is None:
        handle = control

    if handle is None or not objExists(handle):
        printWarningStr("no ikHandle specified")
        return

    #if we weren't passed in joints - discover them now
    if joints is None:
        joints = getJointsFromIkHandle(handle)

    alignFast(control, joints[2])
    if poleControl:
        if objExists(poleControl):
            pos = findPolePosition(joints[2], joints[1], joints[0])
            move(pos[0],
                 pos[1],
                 pos[2],
                 poleControl,
                 a=True,
                 ws=True,
                 rpr=True)
            setKeyframe(poleControl)

    setAttr('%s.%s' % (control, attrName), onValue)
    if key:
        setKeyframe(control, at=('t', 'r'))
        if not _isBatchMode:
            setKeyframe(control, at=attrName)
Beispiel #21
0
def switchToFk(control,
               handle=None,
               attrName='ikBlend',
               onValue=1,
               offValue=0,
               key=False,
               joints=None):
    if handle is None:
        handle = control

    if handle is None or not objExists(handle):
        printWarningStr("no ikHandle specified")
        return

    #if we weren't passed in joints - discover them now
    if joints is None:
        joints = getJointsFromIkHandle(handle)

    #make sure ik is on before querying rotations
    setAttr('%s.%s' % (control, attrName), onValue)
    rots = []
    for j in joints:
        rot = getAttr("%s.r" % j)[0]
        rots.append(rot)

    #now turn ik off and set rotations for the joints
    setAttr('%s.%s' % (control, attrName), offValue)
    for j, rot in zip(joints, rots):
        for ax, r in zip(('x', 'y', 'z'), rot):
            if getAttr('%s.r%s' % (j, ax), se=True):
                setAttr('%s.r%s' % (j, ax), r)

    alignFast(joints[2], handle)
    if key:
        setKeyframe(joints)
        setKeyframe('%s.%s' % (control, attrName))
Beispiel #22
0
def switchToIk( control, poleControl=None, handle=None, attrName='ikBlend', onValue=1, key=False, joints=None, _isBatchMode=False ):
	if handle is None:
		handle = control

	if handle is None or not objExists( handle ):
		printWarningStr( "no ikHandle specified" )
		return

	#if we weren't passed in joints - discover them now
	if joints is None:
		joints = getJointsFromIkHandle( handle )

	alignFast( control, joints[2] )
	if poleControl:
		if objExists( poleControl ):
			pos = findPolePosition( joints[2], joints[1], joints[0] )
			move( pos[0], pos[1], pos[2], poleControl, a=True, ws=True, rpr=True )
			setKeyframe( poleControl )

	setAttr( '%s.%s' % (control, attrName), onValue )
	if key:
		setKeyframe( control, at=('t', 'r') )
		if not _isBatchMode:
			setKeyframe( control, at=attrName )
Beispiel #23
0
		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 )
Beispiel #24
0
def loadWeights( objects, filepath=None, usePosition=True, tolerance=TOL, axisMult=None, swapParity=True, averageVerts=True, doPreview=False, meshNameRemapDict=None, jointNameRemapDict=None ):
	'''
	loads weights back on to a model given a file
	'''

	#nothing to do...
	if not objects:
		print 'No objects given...'
		return

	if filepath is None:
		filepath = getDefaultPath()

	if not filepath.exists():
		print 'File does not exist %s' % filepath
		return

	start = time.clock()


	#setup the mappings
	VertSkinWeight.MESH_NAME_REMAP_DICT = meshNameRemapDict
	VertSkinWeight.JOINT_NAME_REMAP_DICT = jointNameRemapDict


	#cache heavily access method objects as locals...
	skinPercent = cmd.skinPercent
	progressWindow = cmd.progressWindow
	xform = cmd.xform


	#now get a list of all weight files that are listed on the given objects - and
	#then load them one by one and apply them to the appropriate objects
	objItemsDict = {}
	for obj in objects:
		items = []  #this holds the vert list passed in IF any
		if obj.find('.') != -1:
			items = [obj]
			obj = obj.split('.')[0]

		try: objItemsDict[obj].extend( items )
		except KeyError: objItemsDict[obj] = items


	numItems = len(objItemsDict)
	curItem = 1
	progressWindow(e=True, title='loading weights from file %d items' % numItems)


	#load the data from the file
	miscData, joints, jointHierarchies, weightData = Path( filepath ).unpickle()


	#build the search tree
	tree = BinarySearchTree( weightData )
	findMethod = tree.getWithin
	findMethodKw = { 'tolerance': tolerance }

	if averageVerts:
		findMethod = tree.getWithinRatio
		findMethodKw = { 'ratio': tolerance }


	#see if the file versions match
	if miscData[ presets.kEXPORT_DICT_TOOL_VER ] != TOOL_VERSION:
		printWarningStr( "WARNING: the file being loaded was stored from an older version (%d) of the tool - please re-generate the file.  Current version is %d." % (miscData[ presets.kEXPORT_DICT_TOOL_VER ], TOOL_VERSION) )


	#the miscData contains a dictionary with a bunch of data stored from when the weights was saved - do some
	#sanity checking to make sure we're not loading weights from some completely different source
	curFile = cmd.file(q=True, sn=True)
	origFile = miscData['scene']
	if curFile != origFile:
		printWarningStr( 'the file these weights were saved in a different file from the current: "%s"' % origFile )


	#remap joint names in the saved file to joint names that are in the scene - they may be namespace differences...
	missingJoints = set()
	for n, j in joints.iteritems():
		if not cmd.objExists(j):
			#see if the joint with the same leaf name exists in the scene
			idxA = j.rfind(':')
			idxB = j.rfind('|')
			idx = max(idxA, idxB)
			if idx != -1:
				leafName = j[idx + 1:]
				if objExists( leafName ):
					joints[n] = leafName
				else:
					search = cmd.ls('%s*' % leafName, r=True, type='joint')
					if search:
						joints[n] = search[0]
						print '%s remapped to %s' % (j, search[0])


	#now that we've remapped joint names, we go through the joints again and remap missing joints to their nearest parent
	#joint in the scene - NOTE: this needs to be done after the name remap so that parent joint names have also been remapped
	for n, j in joints.iteritems():
		if not cmd.objExists(j):
			dealtWith = False
			for jp in jointHierarchies[n]:
				if cmd.objExists( jp ):
					joints[n] = jp
					dealtWith = True
					break

			if dealtWith:
				print '%s remapped to %s' % (j, jp)
				continue

			missingJoints.add(n)

	#now remove them from the list
	[ joints.pop(n) for n in missingJoints ]


	#axisMults can be used to alter the positions of verts saved in the weightData array - this is mainly useful for applying
	#weights to a mirrored version of a mesh - so weights can be stored on meshA, meshA duplicated to meshB, and then the
	#saved weights can be applied to meshB by specifying an axisMult=(-1,1,1) OR axisMult=(-1,)
	if axisMult is not None:
		for data in weightData:
			for n, mult in enumerate(axisMult): data[n] *= mult

		#we need to re-sort the weightData as the multiplication could have potentially reversed things...  i could probably
		#be a bit smarter about when to re-order, but its not a huge hit...  so, meh
		weightData = sortByIdx(weightData)

		#using axisMult for mirroring also often means you want to swap parity tokens on joint names - if so, do that now.
		#parity needs to be swapped in both joints and jointHierarchies
		if swapParity:
			for joint, target in joints.iteritems():
				joints[joint] = str( names.Name(target).swap_parity() )
			for joint, parents in jointHierarchies.iteritems():
				jointHierarchies[joint] = [str( names.Name(p).swap_parity() ) for p in parents]


	for geo, items in objItemsDict.iteritems():
		#if the geo is None, then check for data in the verts arg - the user may just want weights
		#loaded on a specific list of verts - we can get the geo name from those verts
		skinCluster = ''
		verts = cmd.ls(cmd.polyListComponentConversion(items if items else geo, toVertex=True), fl=True)


		#do we have a skinCluster on the geo already?  if not, build one
		skinCluster = cmd.ls(cmd.listHistory(geo), type='skinCluster')
		if not skinCluster:
			skinCluster = cmd.skinCluster(geo,joints.values())[0]
			verts = cmd.ls(cmd.polyListComponentConversion(geo, toVertex=True), fl=True)
		else: skinCluster = skinCluster[0]


		#if we're using position, the restore weights path is quite different
		vertJointWeightData = []
		if usePosition:
			progressWindow( e=True, status='searching by position: %s (%d/%d)' % (geo, curItem, numItems), maxValue=len( verts ) )

			vCount = -1
			for vert in verts:
				vCount += 1
				pos = Vector( xform(vert, q=True, ws=True, t=True) )
				foundVerts = findMethod( pos, **findMethodKw )


				#accumulate found verts
				jointWeightDict = {}
				for v in foundVerts:
					for joint, weight in zip( v.joints, v.weights ):
						actualJoint = joints[ joint ]
						weight += jointWeightDict.get( actualJoint, 0 )
						jointWeightDict[ actualJoint ] = weight


				#normalize the weights
				weightSum = float( sum( jointWeightDict.values() ) )
				if weightSum != 1:
					for joint, weight in jointWeightDict.iteritems():
						jointWeightDict[ joint ] = weight / weightSum


				#append the data
				vertJointWeightData.append( (vert, jointWeightDict.items()) )


				#deal with the progress window - this isn't done EVERY vert because its kinda slow...
				if vCount % 50 == 0:
					progressWindow( e=True, progress=vCount )

					#bail if we've been asked to cancel
					if progressWindow( q=True, isCancelled=True ):
						progressWindow( ep=True )
						return

			progressWindow( e=True, status='maya is setting skin weights...' )
			setSkinWeights( skinCluster, vertJointWeightData )

		#otherwise simply restore by id
		else:
			progressWindow( e=True, status='searching by vert name: %s (%d/%d)' % (geo, curItem, numItems), maxValue=len( verts ) )

			#rearrange the weightData structure so its ordered by vertex name
			weightDataById = {}
			[ weightDataById.setdefault(i.getVertName(), (i.joints, i.weights)) for i in weightData ]

			for vert in verts:
				#progressWindow(edit=True, progress=cur / num * 100.0)
				#if progressWindow(q=True, isCancelled=True):
					#progressWindow(ep=True)
					#return

				#cur += 1
				try:
					jointList, weightList = weightDataById[vert]
				except KeyError:
					#in this case, the vert doesn't exist in teh file...
					print '### no point found for %s' % vert
					continue
				else:
					jointList = [ joints[ j ] for j in jointList ]
					jointsAndWeights = zip(jointList, weightList)
					skinPercent(skinCluster, vert, tv=jointsAndWeights)

		#remove unused influences from the skin cluster
		cmd.skinCluster( skinCluster, edit=True, removeUnusedInfluence=True )
		curItem += 1

	end = time.clock()
	print 'time for weight load %.02f secs' % (end-start)
Beispiel #25
0
def propagateWeightChangesToModel( meshes ):
	'''
	Given a list of meshes to act on, this function will store the skin weights, remove any
	edits from the skin clusters that affect them, open the scene file the meshes come from
	and apply the weights to the geometry in that scene.

	This makes it possible to fix skinning problems while animating with minimal workflow
	changes
	'''
	curFile = Path( file( q=True, sn=True ) )
	referencedMeshes = getRefFilepathDictForNodes( meshes )

	if not curFile.name():
		printWarningStr( "The current scene isn't saved - please save the current scene first before proceeding!" )
		return

	for refFilepath, refNodeMeshDict in referencedMeshes.iteritems():
		referencesToUnload = []

		#make sure we don't visit any of the meshes more than once
		meshesToUpdateWeightsOn = []
		meshesToUpdateWeightsOn_withNS = []
		for refNode, refMeshes in refNodeMeshDict.iteritems():

			#get the maya filepath for the reference (with the "copy number")
			mayaFilepathForRef = referenceQuery( refNode, f=True )

			#get the namespace for this reference
			refNodeNamespace = file( mayaFilepathForRef, q=True, namespace=True )

			#check to see if there are any meshes in this reference that we need to store weights for
			for mesh_withNS in refMeshes:
				mesh = stripNamespaceFromNamePath( mesh_withNS, refNodeNamespace )
				if mesh in meshesToUpdateWeightsOn:
					continue

				meshesToUpdateWeightsOn.append( mesh )
				meshesToUpdateWeightsOn_withNS.append( (mesh_withNS, refNodeNamespace) )

			#append the file to the list of reference files that we need to unload
			referencesToUnload.append( mayaFilepathForRef )

		#get a list of skin cluster nodes - its actually the skin cluster nodes we want to remove edits from...
		nodesToCleanRefEditsFrom = []
		for m, ns in meshesToUpdateWeightsOn_withNS:
			nodesToCleanRefEditsFrom.append( mel.findRelatedSkinCluster( m ) )

		#now we want to store out the weighting from the referenced meshes
		weights = []
		for mesh, meshNamespace in meshesToUpdateWeightsOn_withNS:
			weights.append( storeWeightsById( mesh, meshNamespace ) )

			#also lets remove any ref edits from the mesh and all of its shape nodes - this isn't strictly nessecary, but I can't think of a reason to make edits to these nodes outside of their native file
			nodesToCleanRefEditsFrom.append( mesh )
			nodesToCleanRefEditsFrom += listRelatives( mesh, s=True, pa=True ) or []

		#remove the skinweights reference edits from the meshes in the current scene
		for f in referencesToUnload:
			file( f, unloadReference=True )

		#remove ref edits from the shape node as well - this isn't strictly nessecary but there probably shouldn't be changes to the shape node anyway
		for node in nodesToCleanRefEditsFrom:
			referenceEdit( node, removeEdits=True, successfulEdits=True, failedEdits=True )

		#re-load references
		for f in referencesToUnload:
			file( f, loadReference=True )

		#save this scene now that we've removed ref edits
		ensureCurrentFileIsCheckedOut()
		file( save=True, f=True )

		#load up the referenced file and apply the weighting to the meshes in that scene
		file( refFilepath, open=True, f=True )

		for mesh, weightData in zip( meshesToUpdateWeightsOn, weights ):

			#if there is no weight data to store - keep loopin...
			if not weightData:
				continue

			skinCluster = mel.findRelatedSkinCluster( mesh )
			if not skinCluster:
				printWarningStr( "Couldn't find a skin cluster driving %s - skipping this mesh" % mesh )
				continue

			skinWeights.setSkinWeights( skinCluster, weightData )

		#save the referenced scene now that we've applied the weights to it
		ensureCurrentFileIsCheckedOut()
		file( save=True, f=True )

	#reload the original file
	file( curFile, o=True, f=True )
Beispiel #26
0
def getControlsFromObjs(control):
    '''
	attempts to retrieve the pole vector control, the ik handle and all fk controls given an ik rig control.  The
	information is returned in a 3 tuple containing:

	ikHandle, poleControl, fkControls
	'''
    errorValue = None, None, None, None

    try:
        part = rigPrimitives.RigPart.InitFromItem(control)

        return part.getControl('control'), part.getIkHandle(), part.getControl(
            'poleControl'), part.getFkControls()
    except rigPrimitives.RigPartError:
        pass

    #so if the control we've been given isn't a rig primitive, lets try to extract whatever information we can from right click commands - if any exist
    trigger = Trigger(ikControl)
    switchCmdStr = None
    for n, cmdName, cmdStr in trigger.iterMenus():
        if cmdName.lower() == _IK_CMD_NAME:
            switchCmdStr = trigger.resolve(cmdStr)
            break

    if switchCmdStr is None:
        printWarningStr("Cannot find the %s command - aborting!" %
                        _IK_CMD_NAME)
        return errorValue

    #extract the control handle from the switch command - it may or may not exist, depending on which
    rexStr = re.compile('-ikHandle \%([a-ZA-Z0-9_:|]+)',
                        re.IGNORECASE | re.MULTILINE)
    match = rexStr.search(switchCmdStr)
    if not match:
        if match.groups()[0]:
            control = match.groups()[0]

    #extract the ik handle from the switch command
    rexStr = re.compile('-ikHandle \%([a-ZA-Z0-9_:|]+)',
                        re.IGNORECASE | re.MULTILINE)
    match = rexStr.search(switchCmdStr)
    if not match:
        printWarningStr(
            "Could not determine the ik handle from the given control")
        return errorValue

    handle = match.groups()[0]
    if handle is None:
        printWarningStr(
            "Could not find the ik handle at the given connect index!")
        return errorValue

    #now extract the pole control from the switch command
    rexStr = re.compile('-pole \%([a-ZA-Z0-9_:|]+)',
                        re.IGNORECASE | re.MULTILINE)
    match = rexStr.search(switchCmdStr)
    if not match:
        printWarningStr(
            "Could not determine the pole vector control from the given control"
        )
        return errorValue

    poleControl = match.groups()[0]
    if poleControl is None:
        printWarningStr(
            "Could not find the ik handle at the given connect index!")
        return errorValue

    return control, poleControl, handle, getJointsFromIkHandle(handle)
Beispiel #27
0
def changeParent(parent=0, objs=None):
    if objs is None:
        objs = ls(sl=True, type='transform') or []

    #only bother with objects that have a "parent" attribute and whose parent attribute value is not the same as the one we've been passed
    objsToActOn = []
    for obj in objs:
        if objExists('%s.parent' % obj):
            objsToActOn.append(obj)

    objs = objsToActOn

    #if there are no objects, bail
    if not objs:
        printWarningStr("There are no objects to work on - aborting!")
        return

    #store the initial time so we can restore it at the end
    initialTime = currentTime(q=True)

    #first we need to make sure that any frame with a rotation key needs to have a key on ALL rotation axes - so make this happen
    keyTimes = keyframe(objs, q=True, at=('t', 'r'), tc=True)
    if not keyTimes:
        printWarningStr("No keys found on the objects - nothing to do!")
        return

    #remove duplicate key times and sort them
    keyTimes = removeDupes(keyTimes)
    keyTimes.sort()

    #store the objects that each have keys at each key time in a dict so we don't have to query maya again. maya queries are slower than accessing python data structures
    timeObjs = {}
    for time in keyTimes:
        currentTime(time, e=True)
        timeObjs[time] = objsWithKeysAtThisTime = []
        for obj in objs:
            keyOnCurrentTime = keyframe(obj,
                                        q=True,
                                        t=(time, ),
                                        at=('parent', 't', 'r'),
                                        kc=True)
            if keyOnCurrentTime:
                setKeyframe(obj, at=('parent', 't', 'r'))
                objsWithKeysAtThisTime.append(obj)

    #now that we've secured the translation/rotation poses with keys on all axes, change the parent on each keyframe
    for time, objsWithKeysAtThisTime in timeObjs.iteritems():
        currentTime(time, e=True)
        for obj in objsWithKeysAtThisTime:
            pos = xform(obj, q=True, rp=True, ws=True)
            rot = xform(obj, q=True, ro=True, ws=True)

            #change the parent and move/rotate back to the original world space pose
            setAttr('%s.parent' % obj, parent)

            move(pos[0], pos[1], pos[2], obj, ws=True, rpr=True)
            rotate(rot[0], rot[1], rot[2], obj, ws=True)

            #lock in the pose
            setKeyframe(obj, at=('parent', 't', 'r'))

    #finally restore the initial time
    currentTime(initialTime, e=True)
Beispiel #28
0
def saveWeights( geos, filepath=None ):
	start = time.clock()
	miscData = {}

	#if filepath is None, then generate a default filepath based on the location of the file
	if filepath is None:
		filepath = getDefaultPath()
	else: filepath = Path(filepath)

	geoAndData = {}
	skinPercent = cmd.skinPercent
	xform = cmd.xform

	#define teh data we're gathering
	masterJointList = []
	weightData = []

	#data gathering time!
	rigidBindObjects = []
	for geo in geos:
		skinClusters = cmd.ls( cmd.listHistory( geo ), type='skinCluster' )
		if len( skinClusters ) > 1:
			printWarningStr( "more than one skinCluster found on %s" % geo )
			continue

		#so the geo isn't skinned in the traditional way - check to see if it is parented to a joint.  if so,
		#stuff it into the rigid bind list to be dealt with outside this loop, and continue
		if not skinClusters:
			dealtWith = False
			for p in iterParents( geo ):
				if cmd.nodeType( p ) == 'joint':
					rigidBindObjects.append( (geo, p) )
					masterJointList.append( p )
					masterJointList = removeDupes( masterJointList )
					dealtWith = True
					break

			if not dealtWith:
				msg = "cannot find a skinCluster for %s" % geo
				printWarningStr( msg )

			continue

		skinCluster = skinClusters[ 0 ]
		masterJointList += cmd.skinCluster( skinCluster, q=True, inf=True )
		masterJointList = removeDupes( masterJointList )

		verts = cmd.ls(cmd.polyListComponentConversion(geo, toVertex=True), fl=True)
		for idx, vert in enumerate(verts):
			jointList = skinPercent(skinCluster, vert, ib=1e-4, q=True, transform=None)
			weightList = skinPercent(skinCluster, vert, ib=1e-4, q=True, value=True)
			if jointList is None:
				raise SkinWeightException("I can't find any joints - sorry.  do you have any post skin cluster history???")

			pos = xform(vert, q=True, ws=True, t=True)
			vertData = VertSkinWeight( pos )
			vertData.populate( geo, idx, [ masterJointList.index( j ) for j in jointList ], weightList )
			weightData.append( vertData )


	#deal with rigid bind objects
	for geo, j in rigidBindObjects:

		verts = cmd.ls( cmd.polyListComponentConversion(geo, toVertex=True), fl=True )
		for idx, vert in enumerate( verts ):
			jIdx = masterJointList.index( j )

			pos = xform( vert, q=True, ws=True, t=True )
			vertData = VertSkinWeight( pos )
			vertData.populate( geo, idx, [jIdx], [1] )
			weightData.append( vertData )


	#sort the weightData by ascending x values so we can search faster
	weightData.sort()

	#turn the masterJointList into a dict keyed by index
	joints = {}
	for n, j in enumerate( masterJointList ):
		joints[ n ] = j

	#generate joint hierarchy data - so if joints are missing on load we can find the best match
	jointHierarchies = {}
	for n, j in joints.iteritems():
		jointHierarchies[ n ] = getAllParents( j )

	toWrite = miscData, joints, jointHierarchies, weightData

	filepath = Path( filepath )
	filepath.pickle( toWrite, False )
	print 'Weights Successfully Saved to %s: time taken %.02f seconds' % (filepath, time.clock()-start)

	return filepath
Beispiel #29
0
    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)
Beispiel #30
0
        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)
Beispiel #31
0
def propagateWeightChangesToModel(meshes):
    '''
	Given a list of meshes to act on, this function will store the skin weights, remove any
	edits from the skin clusters that affect them, open the scene file the meshes come from
	and apply the weights to the geometry in that scene.

	This makes it possible to fix skinning problems while animating with minimal workflow
	changes
	'''
    curFile = Path(file(q=True, sn=True))
    referencedMeshes = getRefFilepathDictForNodes(meshes)

    if not curFile.name():
        printWarningStr(
            "The current scene isn't saved - please save the current scene first before proceeding!"
        )
        return

    for refFilepath, refNodeMeshDict in referencedMeshes.iteritems():
        referencesToUnload = []

        #make sure we don't visit any of the meshes more than once
        meshesToUpdateWeightsOn = []
        meshesToUpdateWeightsOn_withNS = []
        for refNode, refMeshes in refNodeMeshDict.iteritems():

            #get the maya filepath for the reference (with the "copy number")
            mayaFilepathForRef = referenceQuery(refNode, f=True)

            #get the namespace for this reference
            refNodeNamespace = file(mayaFilepathForRef, q=True, namespace=True)

            #check to see if there are any meshes in this reference that we need to store weights for
            for mesh_withNS in refMeshes:
                mesh = stripNamespaceFromNamePath(mesh_withNS,
                                                  refNodeNamespace)
                if mesh in meshesToUpdateWeightsOn:
                    continue

                meshesToUpdateWeightsOn.append(mesh)
                meshesToUpdateWeightsOn_withNS.append(
                    (mesh_withNS, refNodeNamespace))

            #append the file to the list of reference files that we need to unload
            referencesToUnload.append(mayaFilepathForRef)

        #get a list of skin cluster nodes - its actually the skin cluster nodes we want to remove edits from...
        nodesToCleanRefEditsFrom = []
        for m, ns in meshesToUpdateWeightsOn_withNS:
            nodesToCleanRefEditsFrom.append(mel.findRelatedSkinCluster(m))

        #now we want to store out the weighting from the referenced meshes
        weights = []
        for mesh, meshNamespace in meshesToUpdateWeightsOn_withNS:
            weights.append(storeWeightsById(mesh, meshNamespace))

            #also lets remove any ref edits from the mesh and all of its shape nodes - this isn't strictly nessecary, but I can't think of a reason to make edits to these nodes outside of their native file
            nodesToCleanRefEditsFrom.append(mesh)
            nodesToCleanRefEditsFrom += listRelatives(mesh, s=True,
                                                      pa=True) or []

        #remove the skinweights reference edits from the meshes in the current scene
        for f in referencesToUnload:
            file(f, unloadReference=True)

        #remove ref edits from the shape node as well - this isn't strictly nessecary but there probably shouldn't be changes to the shape node anyway
        for node in nodesToCleanRefEditsFrom:
            referenceEdit(node,
                          removeEdits=True,
                          successfulEdits=True,
                          failedEdits=True)

        #re-load references
        for f in referencesToUnload:
            file(f, loadReference=True)

        #save this scene now that we've removed ref edits
        ensureCurrentFileIsCheckedOut()
        file(save=True, f=True)

        #load up the referenced file and apply the weighting to the meshes in that scene
        file(refFilepath, open=True, f=True)

        for mesh, weightData in zip(meshesToUpdateWeightsOn, weights):

            #if there is no weight data to store - keep loopin...
            if not weightData:
                continue

            skinCluster = mel.findRelatedSkinCluster(mesh)
            if not skinCluster:
                printWarningStr(
                    "Couldn't find a skin cluster driving %s - skipping this mesh"
                    % mesh)
                continue

            skinWeights.setSkinWeights(skinCluster, weightData)

        #save the referenced scene now that we've applied the weights to it
        ensureCurrentFileIsCheckedOut()
        file(save=True, f=True)

    #reload the original file
    file(curFile, o=True, f=True)
Beispiel #32
0
	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 )
Beispiel #33
0
def changeRo(objs=None, ro=XYZ):
    if ro not in ROT_ORDER_STRS:
        raise TypeError("need to specify a valid rotation order - one of: %s" %
                        ' '.join(ROT_ORDER_STRS))

    if objs is None:
        objs = ls(sl=True, type='transform')

    roIdx = list(ROT_ORDER_STRS).index(ro)

    #filter out objects that don't have all 3 rotation axes settable and while we're at it store the rotation orders for each object
    #in a dict - since accessing a python dict is WAY faster than doing a getAttr for each frame in the loop below
    RO_DICT = {}
    objsWithAllChannelsSettable = []

    for obj in objs:
        if not getAttr('%s.r' % obj, se=True):
            printWarningStr(
                "Not all rotation axes on the object %s are settable - skipping!"
                % obj)
            continue

        objRo = getAttr('%s.ro' % obj)

        #if the rotation order of this object is the same as what we're changing it to - skip the object entirely
        if objRo == roIdx:
            printWarningStr(
                "The object %s already has the rotation order %s - skipping!" %
                (obj, ro))
            continue

        RO_DICT[obj] = objRo
        objsWithAllChannelsSettable.append(obj)

    #early out if we have no objects to work on
    objs = objsWithAllChannelsSettable
    if not objs:
        printWarningStr("No objects to act on - exiting")
        return

    #cache the conversion method
    convertToMethod = MATRIX_ROTATION_ORDER_CONVERSIONS_TO[roIdx]

    #construct a key server object to march over keys and objects
    keyServer = KeyServer(objs, True)
    for time in keyServer:
        for obj in keyServer.getNodesAtTime():
            setKeyframe(obj, at='r')

    #now that we're secured the rotation poses with keys on all axes, fix up each rotation value to use the desired rotation order
    for time in keyServer:
        for obj in keyServer.getNodesAtTime():
            currentRoIdx = RO_DICT[obj]

            rot = getAttr('%s.r' % obj)[0]
            rotMatrix = MATRIX_ROTATION_ORDER_CONVERSIONS_FROM[currentRoIdx](
                degrees=True, *rot)

            newRot = convertToMethod(rotMatrix, True)
            setAttr('%s.r' % obj, *newRot)
            setKeyframe(obj, at='r')

    #now change the rotation order to what it should be
    for obj in objs:
        setAttr('%s.ro' % obj, roIdx)