def setRot(obj, r, *args): obj = PyNode(obj) for axis, val in zip('xyz', r): try: obj.attr( 'r' + axis ).set(val) except Exception: pass
def switchSpace(ctl: pm.PyNode, space: str) -> bool: """ Switch a control into a new space Args: ctl: A node with space switching meta data space: The name of the space to switch to Returns: True if the space was changed, false otherwise """ meta_data = meta.getMetaData(ctl, pulse.spaces.SPACECONSTRAINT_METACLASS) space_data = [ s for s in meta_data.get('spaces', []) if s['name'] == space ] if not space_data: return False space_data = space_data[0] index = space_data['index'] # remember world matrix wm = ctl.wm.get() # change space ctl.attr('space').set(index) # restore world matrix pulse.nodes.setWorldMatrix(ctl, wm) return True
def setTrans(obj, t, *args): obj = PyNode(obj) for axis, val in zip('xyz', t): try: obj.attr( 't' + axis ).set(val) except Exception: pass
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 readIdSpec(spec): global _specPlugins #if 'type' in spec: # At some point, say 2024, fully deprecate 'fossil_oldspec' # spec['idtype'] = 'fossil_oldspec' readers = _specPlugins.get( spec['idtype'], (UnknownSpec,) ) if 'ver' in spec: version = spec['ver'] for reader in readers: if reader.version[0] == version[0]: break else: # &&& Is it sensible to default to the latest or error? reader = readers[0] print(reader, 'reader') else: reader = readers[0] # Finally, read the specialized spec but fallback to long, then short names if not found obj = reader.readSpec(spec) if not obj: if objExists(spec['long']): return PyNode(spec['long']) if objExists(spec['short']): return PyNode(spec['short']) return obj
def getRoot(nodes=None, make=None): ''' Returns the root bone, trying to account for case and namespaces or None if not found. `make` should be either 'root' or 'weaponRoot', specifying which to make (always top level) if a root is not found. Can be given a list of nodes to search for the root, ''' names = [ 'b_root', 'b_Root', 'Rig:b_root', 'Rig:b_Root', 'b_weaponRoot', 'Rig:b_weaponRoot' ] if not nodes: # Check if any exist top level first top = ls(assemblies=True) for name in names: if name in top: return PyNode('|' + name) # See if there is a top level obj in a namespace named b_root of any casing. searchNodes = nodes if nodes else ls( assemblies=True ) nodes = [obj for obj in searchNodes if simpleName( obj ).lower() == 'b_root' or simpleName(obj).lower() == 'b_weaponroot'] if len(nodes) == 1: return nodes[0] # Then check if any exist at all (which will fail if several exist in separate groups). for name in names: if objExists( name ): return PyNode( name ) if make: return joint(None, n='b_' + make) else: return None
def animInfoNode(create=True): ''' Returns the MT_AnimationInfoNode, making it if it doesn't exist. ''' animNode = None animNodes = ls('MT_AnimationInfoNode*') if len(animNodes) == 1: animNode = animNodes[0] elif not animNodes: if create: animNode = PyNode( scriptNode(name="MT_AnimationInfoNode", scriptType=0, sourceType=1)) else: return None else: print("Multiple anim nodes found") for obj in animNodes: if simpleName(obj) == 'MT_AnimationInfoNode': return obj else: animNode = animNodes[0] _addSeqAttr(animNode) return PyNode(animNode) # Recast to ensure SequenceNode api
def test_basicBiped(): #gui = main.RigTool() # Make the default biped card.bipedSetup(spineCount=5) # Make all the bones and test their existence select(core.findNode.allCards()) main.RigTool.buildBones() for j in jointsToMake: assert objExists(j), 'Joint ' + j + ' was not made' root = core.findNode.getRoot() assert len(listRelatives(root, ad=True, type='joint')) == (len(jointsToMake) - 1), 'Too many bones were made' # Build the rig spine = PyNode('Spine_card') rigData = spine.rigData rigData['rigCmd'] = 'SplineChest' spine.rigData = rigData select(core.findNode.allCards()) main.RigTool.buildRig()
def fixUnhookedSpaces(ctrl): ''' Preliminary tool to deal with messed up spaces. Right now ONLY deals if there is a space name and destination unhookedup. FILL IN OTHERS WITH ERROR IN NAME??? ''' names = common.getNames(ctrl) space = pdil.dagObj.zero(ctrl, apply=False) constraint = PyNode(parentConstraint(space, q=True)) targetPlugs = constraint.getWeightAliasList() if len(names) != len(targetPlugs): print('There are', len(names), 'but', len(targetPlugs), ', you will need to figure out what is right!') noDriver = {} for i, plug in enumerate(targetPlugs): cons = plug.listConnections(s=True, d=False) if not cons: noDriver[i] = plug # connected = {} unconnected = [] conditions = ctrl.attr(common.ENUM_ATTR).listConnections(type='condition') for c in conditions: con = c.outColorR.listConnections() if con: order = c.secondTerm.get() connected[order] = con[0] else: unconnected.append(c) missingIndex = range(len(targetPlugs)) for i in connected: missingIndex.remove(i) if len(noDriver) == 1 and len(unconnected) == 1: print(noDriver, unconnected) print(connected.keys()) print(missingIndex) print('Autofixing!', noDriver.values()[0], 'is "%s"' % names[missingIndex[0]]) unconnected[0].secondTerm.set(missingIndex[0]) #print( noDriver.values()[0] ) unconnected[0].outColorR >> noDriver.values()[0] if not noDriver and not unconnected: print('All good!') else: print('This had some errors') 'FILL IN OTHERS WITH ERROR IN NAME???'
def findFromIds(ids): ''' Given the dict from `getIds()`, returns an object if possible. ''' if len(ls(ids['short'], r=True)) == 1: return PyNode(ids['short']) if len(ls(ids['long'], r=True)) == 1: return PyNode(ids['long'])
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 findFromIds(ids): ''' Given the dict from `getIds()`, returns an object if possible. ..todo:: Process card path and joint paths, (as defined in `getIds`) ''' if len(ls(ids['short'], r=True)) == 1: return PyNode(ids['short']) if len(ls(ids['long'], r=True)) == 1: return PyNode(ids['long'])
def configure_global(self): """ Configure V-Ray global baking options """ # Create default VRay bake options node # NOTE: Doesn't work in batch mode, assuming already exist # pm.mel.vrayShowDefaultBakeOptions() bake_options = PyNode('vrayDefaultBakeOptions') # Set global bake options # bake_options.setAttr('filenamePrefix', self.cur_version_string) bake_options.setAttr('outputTexturePath', self.output_texture_path)
def ikFkSwitch(obj, start, end): ''' Ik/Fk switch Takes any controller type (ik or fk) and switches to the other. ''' obj = PyNode(obj) if isinstance(obj, fossilNodes.RigController): mainCtrl = obj else: mainCtrl = obj.message.listConnections( type=fossilNodes.RigController)[0] otherCtrl = mainCtrl.getOtherMotionType() # If we are changing to fk... if otherCtrl.fossilCtrlType.get() in ['translate', 'rotate']: if start == end and start is not None: # Might want ikFkRange to handle this distinction activateFk(otherCtrl) else: ikFkRange(otherCtrl, start, end) # If we are changing to ik else: activateIk(otherCtrl, start, end)
def rotate(self, dir, angle): rot = [0, 0, 0] rot[ord(dir) - ord('x')] = angle trans = [ PyNode(obj) for obj in selectedNodes() if objectType(obj) == 'transform' ] trans += [ PyNode(obj).getParent() for obj in selectedNodes() if objectType(obj).startswith('nurbs') ] for obj in set(trans): for shape in core.shape.getShapes(obj): rotate(shape.cv, rot, r=True, os=True)
def loadCardStates(): try: cardStateInfo = json.loads( pdil.text.clipboard.get() ) except Exception: print( 'Valid json was not found in the clipboard' ) return selectedCards = getSelectedCards() # If there is a single card, just apply the data if len(cardStateInfo) == 1 and len(selectedCards) == 1: info = cardStateInfo.values()[0] cardAndInfo = [(selectedCards[0], info)] # Otherwise apply data to as many cards with the same names else: cardAndInfo = [(PyNode(card), info) for card, info in cardStateInfo.items() if objExists(card)] for card, info in cardAndInfo: if 'fossilRigState' in info: card.fossilRigState.set( info['fossilRigState'] ) for side in ('Left', 'Center', 'Right'): for kinematic in ('ik', 'fk'): shapeAttr = 'outputShape' + side + kinematic if shapeAttr in info: card.attr( shapeAttr ).set( info[ shapeAttr ] )
def mainGroup(nodePool=None): ''' Returns the main group containing the rig, named "main", or an object tagged as the main. todo: This logic should mainly go into `mainControls`, and this just returns the first. ''' if nodePool: for n in nodePool: if simpleName(n) == 'main' or n.hasAttr(MAIN_CONTROL_TAG): return n if objExists('|main'): return PyNode('|main') else: # A pymel bug is sometimes returning duplicate nodes main = list(set([ obj for obj in ls( 'main', r=True) if not obj.getParent() ])) if len(main) == 1: return main[0] # No "main" ojbect was found, looking for tags plugs = ls('*.' + MAIN_CONTROL_TAG) if plugs: return plugs[0].node() 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 configure_global(self): """ Configure V-Ray global baking options """ bake_options = PyNode('vrayDefaultBakeOptions') bake_options.setAttr('filenamePrefix', self.cur_version_string) bake_options.setAttr('outputTexturePath', self.output_texture_path) bake_options.setAttr('resolutionX', self.image_width)
def deserializeAllConnections(connections=None): if connections is None: connections = json.loads(core.text.clipboard.get()) for obj, data in connections.items(): if objExists(obj): connect(PyNode(obj), data)
def makeMirrored(reposeJoint): ''' Makes a joint that mirrors the transforms of the given repose joint, possibly returning an already existing one. ''' if hasAttr(reposeJoint, 'mirrorGroup'): con = reposeJoint.mirrorGroup.listConnections() if con: return con[0] else: reposeJoint.addAttr('mirrorGroup', at='message') root = PyNode(reposeJoint.fullPath().split('|', 2)[1]) print(root) for child in root.listRelatives(): if child.name() == 'mirrorGroups': grouper = child break else: grouper = group(em=True, n='mirrorGroups') grouper.inheritsTransform.set(False) grouper.setParent(root) follower = group(em=True) mirror = group(em=True) reposeMirror = group(em=True) pdil.math.multiply(follower.tx, -1) >> mirror.tx follower.ty >> mirror.ty follower.tz >> mirror.tz follower.rx >> mirror.rx pdil.math.multiply(follower.ry, -1) >> mirror.ry pdil.math.multiply(follower.rz, -1) >> mirror.rz parentConstraint(reposeJoint, follower, mo=False) parentConstraint(mirror, reposeMirror) reposeMirror.setParent(reposeJoint) reposeMirror.message >> reposeJoint.mirrorGroup follower.setParent(grouper) mirror.setParent(grouper) return reposeMirror
def addMissingJoints(obj, joints): ''' Adds the given joints to the mesh if they aren't already influencing without affecting the current skinning. ''' boundJoints = skinCluster(obj, q=True, inf=True) missing = [PyNode(j) for j in joints if j not in boundJoints] skinCluster(obj, e=True, addInfluence=missing, weight=0)
def readSpec(self, spec): if 'id' in spec: cards = cmds.ls( '*.fossilRigData', o=True, r=True, l=True ) for card in cards: data = json.loads( cmds.getAttr( card + '.fossilRigData' ) ) if spec['id'] == data.get('id', None): return PyNode(card) return None
def customUp(jnt, arrow=None): if not arrow: arrow = makeArrow() arrow.setParent(jnt.getParent()) arrow.rename('custom_arrow') util.moveTo(arrow, jnt) PyNode(jnt).customUp = arrow return arrow
def rotate(dir, angle, space): rot = [0, 0, 0] rot[ord(dir) - ord('x')] = angle trans = [ PyNode(obj) for obj in selectedNodes() if objectType(obj) == 'transform' ] trans += [ PyNode(obj).getParent() for obj in selectedNodes() if objectType(obj).startswith('nurbs') ] for obj in set(trans): for shape in pdil.shape.getNurbsShapes(obj): if space == 'world': rotate(shape.cv, rot, r=True, ws=True) else: rotate(shape.cv, rot, r=True, os=True)
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 serializeAllConnections(toClipboard=False): visGroup = PyNode(get(create=False)) connections = {} for plug in visGroup.listAttr(ud=True, s=True, w=True): for node in plug.listConnections(): if node.type() == 'condition': for obj in node.listConnections(s=False, d=True): data = getVisGroup(obj) if data: connections[obj.name()] = data else: data = getVisGroup(node) connections[node.name()] = data if toClipboard: core.text.clipboard.set(json.dumps(connections)) else: return connections
def findRelatedSkinCluster(skin): ''' Mel's findRelatedSkinCluster that returns a PyNode. ''' try: skin = mel.findRelatedSkinCluster( str(skin) ) if skin: return PyNode(skin) else: return None except Exception: return None
def activate_ik(chestCtrl): ''' ''' util.alignToMatcher(chestCtrl) matcher = util.getMatcher(chestCtrl) endJoint = PyNode(parentConstraint(matcher, q=True, tl=True)[0]) endBpj = rig.getBPJoint(endJoint) if chestCtrl.isPrimarySide: children = [c.real for c in endBpj.proxyChildren if not c.isHelper] else: children = [ c.realMirror for c in endBpj.proxyChildren if not c.isHelper ] if children: rot = xform(children[0], q=True, ws=True, ro=True) pos = xform(children[0], q=True, ws=True, t=True) # --- midJnt = chestCtrl.subControl['mid'].listRelatives(type='joint')[0] skin = listConnections(midJnt, type='skinCluster') curveShape = skin[0].outputGeometry[0].listConnections(p=True)[0].node() ikHandle = curveShape.worldSpace.listConnections(type='ikHandle')[0] chain = util.getChainFromIk(ikHandle) boundJoints = util.getConstraineeChain(chain) if len(boundJoints) % 2 == 1: #switch_logger.debug('Mid point ODD moved, # bound = {}'.format(len(boundJoints))) i = int(len(boundJoints) / 2) + 1 xform(chestCtrl.subControl['mid'], ws=True, t=xform(boundJoints[i], q=True, ws=True, t=True)) else: i = int(len(boundJoints) / 2) xform(chestCtrl.subControl['mid'], ws=True, t=xform(boundJoints[i], q=True, ws=True, t=True)) #switch_logger.debug('Mid point EVEN moved, # bound = {}'.format(len(boundJoints))) # FK match joints beyond the chest control if children: print(rot, pos) xform(chestCtrl.subControl['offset'], ws=True, ro=rot) xform(chestCtrl.subControl['offset'], ws=True, t=pos) """
def load(jsonfile='', subst={}, remove=[], replace=OrderedDict()): if not jsonfile: data = _loadTempWeight() else: with open(jsonfile, 'r') as fid: data = json.load(fid) for mesh, weightData in data.items(): if subst or remove or replace: processWeightData(weightData, subst, remove, replace) apply( PyNode(mesh), weightData)