예제 #1
0
def getSDKCurvesDrivenByObj(obj):
    curves = []
    attrs = listAttr(obj, k=True, v=True, s=True, m=True) or []
    for attr in attrs:
        curves += getSDKCurves(obj, attr)

    return removeDupes(curves)
예제 #2
0
def writeSetAttrCmd( trigger, connectIdxs=None ):
	cmdToks = []
	assert isinstance( trigger, Trigger )

	if connectIdxs is None:
		connectIdxs = [ idx for _,idx in trigger.connects() ]

	#make sure the zeroth connect isn't in the list and remove duplicates
	connectIdxs = removeDupes( connectIdxs )
	if 0 in connectIdxs:
		connectIdxs.remove( 0 )

	for connectIdx in connectIdxs:
		obj = trigger[connectIdx]
		attrs = cmd.listAttr( obj, k=True, s=True, v=True, m=True ) or []
		objTrigger = Trigger( obj )
		for a in attrs:
			attrPath = '%s.%s' % (obj, a)
			attrType = cmd.getAttr( attrPath, type=True )
			attrValue = cmd.getAttr( attrPath )
			if attrType.startswith( 'double' ):
				cmdToks.append( "setAttr %%%d.%s %0.5f;" % (connectIdx, a, attrValue) )
			else:
				cmdToks.append( "setAttr %%%d.%s %d;" % (connectIdx, a, attrValue) )

	return '\n'.join( cmdToks )
예제 #3
0
def getControlShapeFiles():
    dir = CONTROL_DIRECTORY
    if isinstance(dir, basestring):
        dir = Path(dir)

    if not isinstance(dir, Path) or not dir.exists():
        dir = Path(__file__).up()

    shapes = []
    if dir.exists():
        shapes = [f for f in dir.files() if f.hasExtension('shape')]

    if not shapes:
        searchPaths = map(Path, sys.path)
        searchPaths += map(Path,
                           os.environ.get('MAYA_SCRIPT_PATH', '').split(';'))
        searchPaths = removeDupes(searchPaths)

        for d in searchPaths:
            try:
                shapes += [f for f in d.files() if f.hasExtension('shape')]
            except WindowsError:
                continue

    return shapes
예제 #4
0
def getSDKCurvesDrivenByObj( obj ):
	curves = []
	attrs = listAttr( obj, k=True, v=True, s=True, m=True ) or []
	for attr in attrs:
		curves += getSDKCurves( obj, attr )

	return removeDupes( curves )
예제 #5
0
def autoSkinToVolumeMesh( mesh, skeletonMeshRoot ):
	'''
	given a mesh and the root node for a hierarchy mesh volumes, this function will create
	a skeleton with the same hierarchy and skin the mesh to this skeleton using the mesh
	volumes to determine skin weights
	'''

	#grab a list of meshes under the hierarchy - we need to grab this geo, parent it to a skeleton and transfer defacto weighting to the given mesh
	volumes = listRelatives( skeletonMeshRoot, ad=True, type='mesh', pa=True )

	#now generate the skeleton
	transforms = removeDupes( listRelatives( volumes, p=True, type='transform', pa=True ) or [] )
	jointRemap = {}
	for t in transforms:
		select( cl=True )
		jName = '%s_joint' % t
		if objExists( jName ):
			jName += '#'

		j = joint( n=jName )
		jointRemap[ t ] = j

	#now do parenting
	for t, j in jointRemap.iteritems():
		tParent = listRelatives( t, p=True, pa=True )
		if tParent:
			tParent = tParent[0]
			jParent = jointRemap.get( tParent, None )
		else:
			jParent = None

		if jParent is not None:
			parent( j, jParent )

	#now do positioning
	for t in apiExtensions.sortByHierarchy( transforms ):
		j = jointRemap[ t ]
		pos = xform( t, q=True, ws=True, rp=True )
		move( pos[0], pos[1], pos[2], j, ws=True, rpr=True )

	#duplicate the geometry and parent the geo to the joints in the skeleton we just created - store the duplicates so we can delete them later
	dupes = []
	for t, j in jointRemap.iteritems():
		dupe = apiExtensions.asMObject( duplicate( t, returnRootsOnly=True, renameChildren=True )[0] )
		children = listRelatives( dupe, type='transform', pa=True ) or []
		if children:
			delete( children )

		parent( dupe, j )
		dupes.append( dupe )

	f = saveWeights( map( str, dupes ) )

	loadWeights( [mesh], f, usePosition=True, tolerance=0.5, averageVerts=True, jointNameRemapDict=jointRemap )

	delete( dupes )

	return jointRemap
예제 #6
0
	def on_storeB( self, *a ):
		kw = {}
		if self.UI_file.getValue():
			kw[ 'filepath' ] = Path( self.UI_file.getValue() )

		joints = cmd.ls( type='joint', r=True )
		jointMeshes = removeDupes( cmd.listRelatives( joints, ad=True, pa=True, type='mesh' ) )

		skinWeights.saveWeights( jointMeshes, **kw )
예제 #7
0
def getAutoOffsetAmount( placeObject, joints=None, axis=AX_Z, threshold=0.65 ):
	'''
	returns a value reflecting the distance from the placeObject to the edge of
	the bounding box containing the verts skinned to the joints in the joints list

	the axis controls what edge of the bounding box is used

	if joints is None, [placeObject] is used
	'''
	if joints is None:
		joints = [ placeObject ]
	else:
		joints = removeDupes( [ placeObject ] + joints )  #make sure the placeObject is the first item in the joints list, otherwise the bounds won't be transformed to the correct space

	#get the bounds of the geo skinned to the hand and use it to determine default placement of the slider control
	bounds = rigUtils.getJointBounds( joints )
	offsetAmount = abs( bounds[ axis.isNegative() ][ axis % 3 ] )
	#print bounds[ 0 ].x, bounds[ 0 ].y, bounds[ 0 ].z, bounds[ 1 ].x, bounds[ 1 ].y, bounds[ 1 ].z

	return offsetAmount
예제 #8
0
def getAutoOffsetAmount( placeObject, joints=None, axis=AX_Z, threshold=0.65 ):
	'''
	returns a value reflecting the distance from the placeObject to the edge of
	the bounding box containing the verts skinned to the joints in the joints list

	the axis controls what edge of the bounding box is used

	if joints is None, [placeObject] is used
	'''
	if joints is None:
		joints = [ placeObject ]
	else:
		joints = removeDupes( [ placeObject ] + joints )  #make sure the placeObject is the first item in the joints list, otherwise the bounds won't be transformed to the correct space

	#get the bounds of the geo skinned to the hand and use it to determine default placement of the slider control
	bounds = rigUtils.getJointBounds( joints )
	offsetAmount = abs( bounds[ axis.isNegative() ][ axis % 3 ] )
	#print bounds[ 0 ].x, bounds[ 0 ].y, bounds[ 0 ].z, bounds[ 1 ].x, bounds[ 1 ].y, bounds[ 1 ].z

	return offsetAmount
예제 #9
0
def getControlShapeFiles():
	dir = CONTROL_DIRECTORY
	if isinstance( dir, basestring ):
		dir = Path( dir )

	if not isinstance( dir, Path ) or not dir.exists():
		dir = Path( __file__ ).up()

	shapes = []
	if dir.exists():
		shapes = [ f for f in dir.files() if f.hasExtension( 'shape' ) ]

	if not shapes:
		searchPaths = map( Path, sys.path )
		searchPaths += map( Path, os.environ.get( 'MAYA_SCRIPT_PATH', '' ).split( ';' ) )
		searchPaths = removeDupes( searchPaths )

		for d in searchPaths:
			try: shapes += [ f for f in d.files() if f.hasExtension( 'shape' ) ]
			except WindowsError: continue

	return shapes
예제 #10
0
def buildMenuItems( parent, obj ):
	'''
	build the menuItems in the dagProcMenu - it is possible to set a "kill menu" attribute
	on an object now that will stop the dagMenu building after the objMenu items have been
	added
	'''

	defaultCmdName = "<empty cmd>"
	menusFromConnects = False
	killState = False

	objs = [ obj ] + (listRelatives( obj, pa=True, s=True ) or [])

	#the showMenusFromConnects attribute determines whether the object in question should show right click menus from any items connected to this one via triggered connects
	if objExists( '%s.showMenusFromConnects' % obj ):
		menusFromConnects = getAttr( '%s.showMenusFromConnects' % obj )

	if menusFromConnects:
		connects = Trigger( obj ).connects()
		for connectObj, connectIdx in connects:
			objs.append( connectObj )

	objs = removeDupes( objs )

	#now get a list of objs that have menus - if there are more than one, build section labels, otherwise skip labels
	objsWithMenus = []
	for obj in objs:
		obj = Trigger( obj )
		if obj.menus():
			objsWithMenus.append( obj )

	doLabels = len( objsWithMenus ) > 1

	setParent( parent, m=True )
	for obj in objsWithMenus:

		#if ANY of the objs have the kill state set, turn it on
		if getKillState( obj ):
			killState = True

		tgts, names = spaceSwitching.getSpaceTargetsNames( obj )
		names = [ 'parent to %s' % name for name in names ]
		if objExists( '%s.parent' % obj ):
			curIdx = getAttr( '%s.parent' % obj )
		else: curIdx = None

		if doLabels:
			menuItem( l='---%s Menus---' % str( obj ).split( '|' )[-1].split( ':' )[-1], en=False )

		for idx, cmdName, cmdStr in obj.menus( True ):

			#we need to construct the menu item using mel - because the tool was originally mel and all existing obj menu commands are written in mel
			#so you have to construct the menu item in mel otherwise its assumed the command is python...
			menuCmdToks = [ 'menuItem -l "%s"' % (cmdName or defaultCmdName) ]

			#so if the menu name starts with "parent to " then it assumed to be a menu item built by zooSpaceSwitching
			if cmdStr.startswith( "^parent to " ):
				if curIdx is not None:
					if idx == curIdx:
						menuCmdToks( '-cb 1' )

			if cmdStr:
				menuCmdToks.append( '-c "%s"' % encodeString(cmdStr) )

			mel.eval( ' '.join( menuCmdToks ) )

	#should we die after menu build?
	if not killState:
		menuItem( d=True )
		menuItem( d=True )

	return killState
예제 #11
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
예제 #12
0
from melUtils import mel, printErrorStr

SPACE_WORLD = rigUtils.SPACE_WORLD
SPACE_LOCAL = rigUtils.SPACE_LOCAL
SPACE_OBJECT = rigUtils.SPACE_OBJECT

Axis = rigUtils.Axis
CONTROL_DIRECTORY = None

if CONTROL_DIRECTORY is None:
    #try to determine the directory that contains the control macros
    dirsToSearch = [
        Path(__file__).up()
    ] + sys.path + os.environ['MAYA_SCRIPT_PATH'].split(os.pathsep)
    dirsToSearch = map(Path, dirsToSearch)
    dirsToSearch = removeDupes(dirsToSearch)

    for dirToSearch in dirsToSearch:
        if not dirToSearch.isDir():
            continue

        foundControlDir = False
        for f in dirToSearch.files(recursive=True):
            if f.hasExtension('shape'):
                if f.name().startswith('control'):
                    CONTROL_DIRECTORY = f.up()
                    foundControlDir = True
                    break

        if foundControlDir:
            break
예제 #13
0
def create(trigger,
           control=None,
           linear=True,
           optimize=True,
           preserve=False,
           defaultValue=0,
           maxValue=10):
    '''
	converts poses stored as triggered menu commands on trigger to set driven keys on the given control.  If control is
	None then the trigger itself is used.
	'''
    if not isinstance(trigger, triggered.Trigger):
        trigger = triggered.Trigger(trigger)

    if control is None:
        control = trigger

    cmdData = trigger.menus()

    #gather data about the cmds first
    menuIdxs = []
    menuNames = {}
    connectsUsedByCmds = {}
    cmdStrs = {}
    resolvedCmdStrs = {}
    sliderNames = {}
    sliderBreakdownValues = {}
    for menuIdx, menuName, cmdStr in cmdData:
        menuIdxs.append(menuIdx)
        menuNames[menuIdx] = menuName
        cmdStrs[menuIdx] = cmdStr
        connectsUsedByCmds[menuIdx] = [
            trigger[connectIdx]
            for connectIdx in trigger.getConnectsUsedByCmd(cmdStr)
        ]
        resolvedCmdStrs[menuIdx] = trigger.resolve(cmdStr)

        #determine the slider name from the menu name
        sliderName = menuNames[menuIdx]
        while sliderName.startswith('_'):
            sliderName = sliderName[1:]

        underscoreIdx = sliderName.rfind('_')
        if underscoreIdx != -1:
            try:
                sliderBreakdownValues[menuIdx] = float(
                    sliderName[underscoreIdx + 1:])
            except ValueError:
                pass
            sliderName = sliderName[:underscoreIdx]
        else:
            sliderBreakdownValues[menuIdx] = maxValue

        sliderNames[menuIdx] = sliderName

    def setToDefaultPose():
        melUtils.mel.eval(resolvedCmdStrs[menuIdxs[0]])

    setToDefaultPose()

    #get a list of all target objects, so we know what objects to build SDK curves for
    allUsedConnectIdxs = []
    for connectsUsed in connectsUsedByCmds.values():
        allUsedConnectIdxs += connectsUsed

    allUsedConnects = removeDupes(allUsedConnectIdxs)

    #the user may want to preserve existing sdk data on the target objects...
    if not preserve:
        for connect in allUsedConnects:
            deleteSliders(connect)

    #delete any existing sliders
    for menuIdx in menuIdxs:
        sliderName = sliderNames[menuIdx]
        attrpath = '%s.%s' % (control, sliderName)
        if objExists(attrpath):
            deleteAttr(attrpath)

    #now build the sliders
    for menuIdx in menuIdxs:
        sliderName = sliderNames[menuIdx]
        breakdownVal = sliderBreakdownValues[menuIdx]

        #create the attribute if it doesn't already exist
        attrpath = '%s.%s' % (control, sliderName)
        if not objExists(attrpath):
            addAttr(control, ln=sliderName, at='double', min=0, max=0, dv=0)
            setAttr(attrpath, k=True)

        #now that the attribute is created, see what its limits are, and whether the current limit values should push
        #those limits further
        curMin = addAttr(attrpath, q=True, min=True)
        curMax = addAttr(attrpath, q=True, max=True)

        if breakdownVal < curMin:
            addAttr(attrpath, e=True, min=breakdownVal)
        elif breakdownVal > curMax:
            addAttr(attrpath, e=True, max=breakdownVal)

    #now build the SDKs, we know the attributes exist, so we don't need to worry about them
    sliders = []
    sliderKeyCounts = []
    for menuIdx in menuIdxs[1:]:
        attrpath = '%s.%s' % (control, sliderNames[menuIdx])
        breakdownVal = sliderBreakdownValues[menuIdx]

        #return to default pose
        setAttr(attrpath, defaultValue)
        setToDefaultPose()
        for connect in connectsUsedByCmds[menuIdx]:
            setDrivenKeyframe(connect, cd=attrpath)

        #go into the pose and set its SDK key
        setAttr(attrpath, breakdownVal)
        melUtils.mel.eval(resolvedCmdStrs[menuIdx])
        for connect in connectsUsedByCmds[menuIdx]:
            setDrivenKeyframe(connect, cd=attrpath)

        setAttr(attrpath, defaultValue)

    for connect in allUsedConnectIdxs:
        setCurveInfinityToLinear(connect)
        if optimize:
            deleteStaticChannels(connect)

        if linear:
            setTangentsTo(connect, 'linear')
예제 #14
0
def create( trigger,
            control=None,
            linear=True,
            optimize=True,
            preserve=False,
            defaultValue=0,
            maxValue=10 ):
	'''
	converts poses stored as triggered menu commands on trigger to set driven keys on the given control.  If control is
	None then the trigger itself is used.
	'''
	if not isinstance( trigger, triggered.Trigger ):
		trigger = triggered.Trigger( trigger )

	if control is None:
		control = trigger

	cmdData = trigger.menus()

	#gather data about the cmds first
	menuIdxs = []
	menuNames = {}
	connectsUsedByCmds = {}
	cmdStrs = {}
	resolvedCmdStrs = {}
	sliderNames = {}
	sliderBreakdownValues = {}
	for menuIdx, menuName, cmdStr in cmdData:
		menuIdxs.append( menuIdx )
		menuNames[menuIdx] = menuName
		cmdStrs[menuIdx] = cmdStr
		connectsUsedByCmds[menuIdx] = [ trigger[connectIdx] for connectIdx in trigger.getConnectsUsedByCmd( cmdStr ) ]
		resolvedCmdStrs[menuIdx] = trigger.resolve( cmdStr )

		#determine the slider name from the menu name
		sliderName = menuNames[menuIdx]
		while sliderName.startswith( '_' ):
			sliderName = sliderName[1:]

		underscoreIdx = sliderName.rfind( '_' )
		if underscoreIdx != -1:
			try: sliderBreakdownValues[menuIdx] = float( sliderName[underscoreIdx+1:] )
			except ValueError: pass
			sliderName = sliderName[:underscoreIdx]
		else:
			sliderBreakdownValues[menuIdx] = maxValue

		sliderNames[menuIdx] = sliderName

	def setToDefaultPose(): melUtils.mel.eval( resolvedCmdStrs[ menuIdxs[0] ] )
	setToDefaultPose()

	#get a list of all target objects, so we know what objects to build SDK curves for
	allUsedConnectIdxs = []
	for connectsUsed in connectsUsedByCmds.values():
		allUsedConnectIdxs += connectsUsed

	allUsedConnects = removeDupes( allUsedConnectIdxs )

	#the user may want to preserve existing sdk data on the target objects...
	if not preserve:
		for connect in allUsedConnects:
			deleteSliders( connect )

	#delete any existing sliders
	for menuIdx in menuIdxs:
		sliderName = sliderNames[menuIdx]
		attrpath = '%s.%s' % (control, sliderName)
		if objExists( attrpath ):
			deleteAttr( attrpath )

	#now build the sliders
	for menuIdx in menuIdxs:
		sliderName = sliderNames[menuIdx]
		breakdownVal = sliderBreakdownValues[menuIdx]

		#create the attribute if it doesn't already exist
		attrpath = '%s.%s' % (control, sliderName)
		if not objExists( attrpath ):
			addAttr( control, ln=sliderName, at='double', min=0, max=0, dv=0 )
			setAttr( attrpath, k=True )

		#now that the attribute is created, see what its limits are, and whether the current limit values should push
		#those limits further
		curMin = addAttr( attrpath, q=True, min=True )
		curMax = addAttr( attrpath, q=True, max=True )

		if breakdownVal < curMin:
			addAttr( attrpath, e=True, min=breakdownVal )
		elif breakdownVal > curMax:
			addAttr( attrpath, e=True, max=breakdownVal )

	#now build the SDKs, we know the attributes exist, so we don't need to worry about them
	sliders = []
	sliderKeyCounts = []
	for menuIdx in menuIdxs[1:]:
		attrpath = '%s.%s' % (control, sliderNames[menuIdx])
		breakdownVal = sliderBreakdownValues[menuIdx]

		#return to default pose
		setAttr( attrpath, defaultValue )
		setToDefaultPose()
		for connect in connectsUsedByCmds[menuIdx]:
			setDrivenKeyframe( connect, cd=attrpath )

		#go into the pose and set its SDK key
		setAttr( attrpath, breakdownVal )
		melUtils.mel.eval( resolvedCmdStrs[menuIdx] )
		for connect in connectsUsedByCmds[menuIdx]:
			setDrivenKeyframe( connect, cd=attrpath )

		setAttr( attrpath, defaultValue )

	for connect in allUsedConnectIdxs:
		setCurveInfinityToLinear( connect )
		if optimize:
			deleteStaticChannels( connect )

		if linear:
			setTangentsTo( connect, 'linear' )
예제 #15
0
from apiExtensions import asMObject, MObject
from melUtils import mel, printErrorStr

SPACE_WORLD = rigUtils.SPACE_WORLD
SPACE_LOCAL = rigUtils.SPACE_LOCAL
SPACE_OBJECT = rigUtils.SPACE_OBJECT

Axis = rigUtils.Axis
CONTROL_DIRECTORY = None

if CONTROL_DIRECTORY is None:
	#try to determine the directory that contains the control macros
	dirsToSearch = [ Path( __file__ ).up() ] + sys.path + os.environ[ 'MAYA_SCRIPT_PATH' ].split( os.pathsep )
	dirsToSearch = map( Path, dirsToSearch )
	dirsToSearch = removeDupes( dirsToSearch )

	for dirToSearch in dirsToSearch:
		if not dirToSearch.isDir():
			continue

		foundControlDir = False
		for f in dirToSearch.files( recursive=True ):
			if f.hasExtension( 'shape' ):
				if f.name().startswith( 'control' ):
					CONTROL_DIRECTORY = f.up()
					foundControlDir = True
					break

		if foundControlDir:
			break