def setCurveColor(ctrl, newColor): ''' newColor can an indexed color or you can specify RGB. NOTE!!! RGB is NOT currently saved. ''' curves = [ c for c in cmds.listRelatives(ctrl.name(), type='nurbsCurve', f=True) if core.shape.isValidNurbsCurve(c) ] surfaces = cmds.listRelatives(ctrl.name(), type='nurbsSurface', f=True) if surfaces: curves += surfaces for shape in curves: try: cmds.setAttr(shape + '.overrideEnabled', True) if isinstance(newColor, int): cmds.setAttr(shape + '.overrideColor', newColor) cmds.setAttr(shape + '.overrideRGBColors', False) else: cmds.setAttr(shape + '.overrideRGBColors', True) cmds.setAttr(shape + '.overrideColorRGB', *newColor) except Exception: pass
def assign(obj, color): ''' Assign a shader of the given color and opacity, reusing shaders when possible. ''' global namedColors if isinstance(color, basestring): color = parseStr(color) if len(color) == 3: color = list(color) + [1.0] shaders = findShaders(color) if not shaders: # No existing shader was found, so make it. shader = createShader(color) sg = shader.outColor.listConnections(type='shadingEngine')[0] else: # Matching shaders were found, find one that is valid. for shader in shaders: if shader.outColor.listConnections(type='shadingEngine'): sg = shader.outColor.listConnections(type='shadingEngine')[0] break # Or end up making one anyway. else: shader = createShader(color) sg = shader.outColor.listConnections(type='shadingEngine')[0] # cmds is much faster, but `sets` vs `pymel.core.sets` has different args (pymel made it saner but I need speed) cmds.sets(cmds.listRelatives(obj.name(), type='nurbsSurface', f=True), e=True, fe=sg.name())
def rootMotion(main=None): ''' Returns the root motion, if main is specified, search that node. ''' if main: children = cmds.listRelatives(main.name(), ad=True, type='transform', f=True) if children: # cmds returns None instead of emtpy list for child in children: if child.rsplit('|', 1)[-1].rsplit(':', 1)[-1] == 'rootMotion': return PyNode(child) return None if objExists('rootMotion'): return PyNode('rootMotion') else: rms = ls('rootMotion', r=True) if len(rms) == 1: return rms[0] return None
def allCards(main=None): ''' Return all the cards, optionally taking a specific skeletonBlueprint. ''' # Use cmds for speed (swift takes 0.20 with pymel but 0.04 with cmds) targetCards = set( cmds.ls( '*.skeletonInfo', o=True, r=True, l=True ) + cmds.ls( '*.fossilRigData', o=True, r=True, l=True ) ) if main: targetCards.intersection_update( cmds.listRelatives(main.name(), ad=True, type='transform', f=True) ) def order(obj): try: return cmds.getAttr(obj + '.buildOrder') except Exception: pass try: return json.loads(cmds.getAttr(obj + '.fossilRigData')).get('buildOrder', 10) except Exception: pass return 10 return [PyNode(c) for c in sorted(targetCards, key=order)]
def get_slow(mesh): ''' Given a mesh, returns a list, one entry per vertex, with a list of (joint, value) pairs. ex: [0] = [ (ja, .5), (jb, .5) ] [1] = [ (ja, .5), (jb, .25), (jc, .25) ] ''' skinClusterName = mel.findRelatedSkinCluster(mesh) joints = cmds.skinCluster(mesh.name(), q=True, inf=True) weights = [] required = {} for j in joints: parent = cmds.listRelatives(j, p=True) required[j] = [parent[0] if parent else None] + cmds.xform(j, q=True, ws=True, t=True) info = { 'joints': required, 'weights': weights, } vtxStr = mesh.name() + '.vtx[%i]' for i in xrange(mesh.vtx.count()): weights.append( [(t, v) for t, v in zip(joints, cmds.skinPercent(skinClusterName, vtxStr % i, q=1, v=1)) if v > 0] ) return info
def setInputField(self, card, row, param): ''' Given a `Param`, build, and place, the correct ui element for the param's data type. ''' self.params.append(param) if param.type == param.BOOL: checkBox = QtWidgets.QTableWidgetItem() state = Qt.Checked if card.rigData.get('ikParams', {}).get(param.kwargName, param.default) else Qt.Unchecked checkBox.setCheckState( state ) self.setItem( row, 1, checkBox ) elif param.type == param.INT: self.setItem( row, 1, QtWidgets.QTableWidgetItem(str(card.rigData.get('ikParams', {}).get(param.kwargName, param.default))) ) elif param.type == param.FLOAT: self.setItem( row, 1, QtWidgets.QTableWidgetItem(str( card.rigData.get('ikParams', {}).get(param.kwargName, param.default))) ) elif param.type == param.ENUM: dropdown = QtWidgets.QComboBox() dropdown.addItems(param.enum.keys()) #dropdown.currentIndexChanged.connect( partial(self.enumChange, param) ) #for key, val in param.enum.items(): # dropdown.addItem( key ).triggered.connect( partial(self.changeEnum, param.kwargName, val) ) self.setCellWidget(row, 1, dropdown) try: enumVal = param.enum.values().index( card.rigData.get('ikParams', {}).get(param.kwargName, param.default) ) dropdown.setCurrentIndex(enumVal) dropdown.currentIndexChanged.connect( partial(self.enumChange, param=param) ) except: print( 'oerror with', param.kwargName, param.default, card, row ) elif param.type == param.STR: val = card.rigData.get('ikParams', {}).get(param.kwargName, param.default) self.setItem( row, 1, QtWidgets.QTableWidgetItem(val) ) elif param.type in (param.CURVE, param.NODE_0): # Just accept curves, they are all I connect to dropdown = QtWidgets.QComboBox() # Get all the curve transforms under the skeletonBlueprint curves = cmds.listRelatives( cmds.listRelatives('skeletonBlueprint', type='nurbsCurve', f=True, ad=True), p=True, f=True) self.paramSceneOptions[param] = curves if curves: # &&& This can sometimes be empty, which causes the gui to choke on the error (in 2019, but not 2016) dropdown.addItems( curves ) # ERROR? self.setCellWidget(row, 1, dropdown)
def parentName(jnt): parent = cmds.listRelatives(j, p=True) if parent: try: return jointNames.index( parent[0] ) except ValueError: return parent[0] return None
def rootMotion(main=None): ''' Returns the root motion, optionally making one if it doesn't exist. If main is specified, search its descendents. ''' ''' Timing test with Swift as main, re and split are about equal and 200x faster! re and split were almost identical, even on the whole scene. s = time.time() #oldGetRootMotion(main) for child in listRelatives(main, ad=True, type='transform'): #for child in ls(type='transform'): if lib.dagObj.simpleName( child ) == 'rootMotion': break #return child print( time.time() - s, 'orig') s = time.time() for child in cmds.listRelatives(main.name(), ad=True, type='transform'): #for child in cmds.ls(type='transform'): if child.rsplit('|',1)[-1].rsplit(':', 1)[-1] == 'rootMotion': #print( child) break print( time.time() - s, 'split') s = time.time() simpleName = re.compile( '\w+$' ) for child in cmds.listRelatives(main.name(), ad=True, type='transform'): #for child in cmds.ls(type='transform'): if simpleName.search(child).group(0) == 'rootMotion': #print( child) break print( time.time() - s, 're') ''' if main: children = cmds.listRelatives(main.name(), ad=True, type='transform') if children: # cmds returns None instead of emtpy list for child in children: if child.rsplit('|', 1)[-1].rsplit(':', 1)[-1] == 'rootMotion': return PyNode(child) return None if objExists( 'rootMotion' ): return PyNode( 'rootMotion' ) else: rms = ls( 'rootMotion', r=True ) if len(rms) == 1: return rms[0] return None
def find(obj): ''' If there is a shared shape, returns it. If not, returns None. ''' shapes = cmds.listRelatives(obj.name(), type='nurbsCurve', f=True) if not shapes: return None for shape in shapes: if objExists( shape + '.sharedShape' ): return shape return None
def find(obj, shapeType): ''' If `obj` has shared shape of `shapeType`, return it or None if not found. ''' shapes = cmds.listRelatives(obj.name(), type='nurbsCurve', f=True) if not shapes: return None for shape in shapes: if (cmds.attributeQuery(core.shape.SHARED_SHAPE, n=shape, ex=True) and cmds.getAttr(shape + '.' + core.shape.SHARED_SHAPE) == shapeType): return shape return None
def controllers(main=None): ''' Returns all the animation controllers in the scene. .. todo:: Add the shapes that have ik/fk switching on them ''' allControls = set( cmds.ls('*.' + config.FOSSIL_CTRL_TYPE, o=True, r=True, l=True)) if main: mainTransforms = cmds.listRelatives(main.name(), ad=True, type='transform', f=True) if mainTransforms: allControls.intersection_update(mainTransforms) controls = [PyNode(o) for o in allControls] controls.append(main) root = rootMotion(main=main) if root: controls.append(root) return controls else: warning("No sub controls found for {0}".format(main.name())) else: controls = [PyNode(o) for o in allControls] main = mainGroup() if main: controls.append(main) root = rootMotion(main=main) if root: controls.append(root) return controls return []
def getSwitcherPlug(obj): ''' Will return either a string like "Arm_L_FKIK_SWITCH" or empty string if no switcher is found. Can't use pymel to avoid warnings of invalid node (nurbs with no cvs). This also means listRelatives returns None instead of []. Lame. ''' shapes = cmds.listRelatives(str(obj), type='nurbsCurve', f=True) if shapes: for shape in shapes: # Check for new style switch first if cmds.objExists(shape + '.IkSwitch'): return shape + '.IkSwitch' # Fallback to old style switch if cmds.objExists(shape + '.kinematicSwitch'): attr = cmds.listAttr(shape, ud=1, st='*_Switch') return cmds.ls(shape, l=False)[0] + '.' + attr[0] # noqa return ''
def controllers(main=None): ''' Returns all the animation controllers in the scene. .. todo:: Add the shapes that have ik/fk switching on them ''' ''' Timing experiments: Results, cmds + sets is WAY faster! s = time.time() controls = [c for c in listRelatives(main, ad=True, type='transform') if c.hasAttr('fossilCtrlType')] print( time.time() - s, 'ls(*.fossilCtrlType) ORIGINAL' ) s = time.time() controls = [PyNode(c) for c in cmds.listRelatives(main.name(), ad=True, type='transform', f=1) if cmds.attributeQuery('fossilCtrlType', node=c, ex=True)] print( time.time() - s, 'cmds.listRelatives() list comp' ) s = time.time() #controls = [c for c in listRelatives(main, ad=True, type='transform') if c.hasAttr('fossilCtrlType')] allControls = set(cmds.ls('*.fossilCtrlType', type='transform', r=True, o=True)) allControls.intersection_update( cmds.listRelatives(main.name(), ad=True, type='transform') ) controls = [PyNode(o) for o in allControls] print( time.time() - s, 'cmds and set filtering' ) Swift Cat as main: 0.611000061035 ls(*.fossilCtrlType) ORIGINAL 0.123000144958 cmds.listRelatives() list comp 0.0439999103546 cmds and set filtering Swift as Main: 2.1210000515 ls(*.fossilCtrlType) ORIGINAL 0.398999929428 cmds.listRelatives() list comp 0.0769999027252 cmds and set filtering ''' allControls = set( cmds.ls( '*.fossilCtrlType', o=True, r=True ) ) if main: mainTransforms = cmds.listRelatives(main.name(), ad=True, type='transform') if mainTransforms: allControls.intersection_update( mainTransforms ) controls = [PyNode(o) for o in allControls] controls.append(main) root = rootMotion(main=main) if root: controls.append(root) return controls else: warning("No sub controls found for {0}".format(main.name())) else: controls = [PyNode(o) for o in allControls] main = mainGroup() if main: controls.append(main) root = rootMotion(main=main) if root: controls.append(root) return controls return []
def generateReposer(cards=None, placeholder=False, progress=None): ''' If no cards are specificed, a new reposer is build, otherwise it rebuilds/adds reposers for the specified cards. Args: cards placeholder progress: Optional `progressWindow` that will be `.update()`'d twice for each card, MUST be preconfigured (in case several things are updating) &&& TODO Verify the cards can be built in any order ''' global jointMapping # global'd for debugging suffix = '_placeholder' if placeholder else '' rJoints = [] rCards = [] unlock = {} # <repose joint or card>: <list of attrs to be re-locked> jointMapping = {} # Lazy "bi-directional mapping" of bpj <-> reposeJoint, both are added as keys to eachother # Build all the cards and joints if not cards: cards = find.blueprintCards() # Delete previous roots for oldRoot in getReposeRoots(): oldRoot.deleteAttr('reposeRoot') # Otherwise populate the containers with the existing reposer to build/add new stuff. else: #allExistingRCards = set( cmds.ls( '*.bpCard', o=True, r=True, l=True ) ) allExistingRJoints = set( cmds.ls( '*.bpj', o=True, r=True, l=True ) ) for oldRoot in getReposeRoots(): joints = cmds.listRelatives( str(oldRoot), f=True, ad=True, type='joint' ) joints = [PyNode(c) for c in allExistingRJoints.intersection(joints)] for rj in joints: bpj = rj.bpj.listConnections()[0] jointMapping[rj] = bpj jointMapping[bpj] = rj for card in cards: if progress: progress.update() rCard = duplicate(card, po=0)[0] showHidden(rCard) pdil.dagObj.unlock(rCard) stripReposerCard(rCard) targetName = simpleName(card, '{}_repose' + suffix) previous, attrs = reposeLink(card, rCard, 'bpCard') if not placeholder else (None, []) unlock[rCard] = attrs renameReposeObj(rCard, targetName, previous) for child in rCard.listRelatives(): if not child.type() == 'nurbsSurface': delete(child) rCards.append(rCard) makeIdentity(rCard, t=False, r=False, s=True, apply=True) pdil.dagObj.lock( rCard, 's' ) for jnt in card.joints: reposeJoint = joint(None) targetName = simpleName(jnt, '{}_repose' + suffix) previous, attrs = reposeLink(jnt, reposeJoint, 'bpj') if not placeholder else (None, []) unlock[reposeJoint] = attrs renameReposeObj(reposeJoint, targetName, previous) pdil.dagObj.matchTo(reposeJoint, jnt) #assert jnt.info.get('options', {}).get('mirroredSide', False) is False, 'parent to mirrored joints not supported yet' jointMapping[jnt] = reposeJoint jointMapping[reposeJoint] = jnt rJoints.append(reposeJoint) # Set their parents for reposeJoint in rJoints: parent = jointMapping[reposeJoint].parent if parent in jointMapping: # Check against joint mapping in case only a few selected cards a being tposed reposeJoint.setParent( jointMapping[parent] ) reposeContainer = getReposeContainer() # Put under cards, card pivot to lead joint for rCard, card in zip(rCards, cards): if progress: progress.update() bpj = card.parentCardJoint #print('BPJ - - - - ', bpj, bpj in jointMapping) if bpj in jointMapping: start = card.start() if card.joints else bpj #rCard.setParent( getRJoint(bpj) ) pdil.dagObj.unlock(rCard) #firstBpj = card.joints[0] #return isMirrored = card.isCardMirrored() mirroredSide = card.joints[0].info.get('options', {}).get('mirroredSide') #print('rCard.mirror', rCard.mirror, 'info:', mirroredSide) #if rCard.mirror is False and mirroredSide: if isMirrored is False and card.mirror is False and mirroredSide: #print('opposite mirror') rCard.setParent( makeMirrored( jointMapping[bpj] ) ) else: #print('regular side stuff') rCard.setParent( jointMapping[bpj] ) #cmds.parent(str(rCard), str(jointMapping[bpj])) xform(rCard, ws=True, piv=xform(start, q=True, t=True, ws=True) ) pdil.dagObj.lock(rCard, 't') else: if not placeholder: rCard.addAttr('reposeRoot', at='message') rCard.setParent( reposeContainer ) addVector(rCard, 'origRot', rCard.r.get()) addVector(rCard, 'origTrans', rCard.t.get()) #start = getRJoint(card.start()) start = jointMapping[card.start()] start.setParent( rCard ) pdil.dagObj.lock( start, 't s' ) if rCard in unlock: for attr in unlock[rCard]: rCard.attr(attr).unlock() rCard.attr(attr).showInChannelBox(True) for reposeJoint in rJoints: pdil.dagObj.lock(reposeJoint, 'ry rz') pdil.dagObj.lock(reposeJoint, 't s') # I can't see why I wasn't locking t/s already. Possible exception, `freeform` if reposeJoint in unlock: for attr in unlock[reposeJoint]: reposeJoint.attr(attr).unlock() reposeJoint.attr(attr).showInChannelBox(True) addVector(reposeJoint, 'origRot', reposeJoint.r.get()) addVector(reposeJoint, 'origTrans', reposeJoint.t.get()) '''
def get_old(mesh): ''' Creates as dictionary that looks like the following: { 'weights': [ ], # index is vertex index, value is list of bone, weight pairs [0] = [ ('j1', .75), ('j2', .25) ]... 'joints': { 'j1': [parent, global_x, global_y, global_z] ... } } ''' ''' DEBUG from pdil.core import capi from maya.api.OpenMayaAnim import MFnSkinCluster ''' skinClusterName = mel.findRelatedSkinCluster(mesh) skinClusterMObj = capi.asMObject( skinClusterName ) skinFn = MFnSkinCluster( skinClusterMObj.object() ) #construct a dict mapping joint names to joint indices jointApiIndices = {} for jointDagMObj in skinFn.influenceObjects(): jointApiIndices[ skinFn.indexForInfluenceObject( jointDagMObj ) ] = jointDagMObj.partialPathName() weightListPlug = skinFn.findPlug( 'weightList', True ) weightListObj = weightListPlug.attribute() weightsPlug = skinFn.findPlug( 'weights', True ) weights = [None] * mesh.vtx.count() # Prebuilding the whole range is nearly instant, appending is probably slower # since it will trigger resizing. for vertIdx in xrange(mesh.vtx.count()): # noqa # We need to use the api to query the physical indices used weightsPlug.selectAncestorLogicalIndex( vertIdx, weightListObj ) activeJointIndices = weightsPlug.getExistingArrayAttributeIndices() # Values = cmds_getAttr( baseFmtStr % vertIdx + '.weights' )[0] # api 2.0 is 0.09 instead of 0.25 values = [weightsPlug.elementByLogicalIndex(i).asDouble() for i in activeJointIndices] try: # If `i` isn't in jointApiIndices, that value is skipped. Not sure why these garbage values are just left behind... weights[vertIdx] = [ (jointApiIndices[idx], v) for idx, v in zip( activeJointIndices, values ) if idx in jointApiIndices] except Exception: raise ''' weights[vertIdx] = [] # This gets hit when an influence object has been removed for i, v in zip(activeJointIndices, values): if v > 0.000001: weights[vertIdx].append( (jointApiIndices[i], v) ) ''' # Prune out the unused joints (Maybe make an option?) joints = {} requiredJoints = set() for wgt in weights: for j, v in wgt: requiredJoints.add(j) # Save the joint's parent and worldspace position, for possible future use/issue detection. for j in requiredJoints: parent = cmds.listRelatives(j, p=True) joints[j] = [parent[0] if parent else None] + cmds.xform(j, q=True, ws=True, t=True) return {'weights': weights, 'joints': joints}