def loadTranslationControl(root_joint, module_name, container, module_control_grp, control_type = "translation", color = [1, 0, 0]): """ loads translation control onto the root_joint """ path = os.path.join(environ.ControlObjectsPath, "translation_control.ma") pm.importFile(path, renameAll = True, loadReferenceDepth = "all", namespace =":") # renamePrefix == namespace # rename default module translation_control = pm.rename("translation_control", module_name + ":" + root_joint.stripNamespace() + "_translation_control", ignoreShape = False) translation_control_grp = pm.group(translation_control, name = module_name + ":" + root_joint.stripNamespace() + "_translation_controlGrp") # move control to root root_joint pm.delete(pm.pointConstraint(root_joint, translation_control_grp, maintainOffset=False)) translation_control_grp.setParent(module_control_grp) pm.addAttr(translation_control, longName="ControlType", dataType="string", keyable=False) pm.addAttr(translation_control, longName="ParentObject", at="message", multi = True) translation_control.ControlType.set(control_type, type = "string", lock = True) utils.addNodeToContainer(container, [translation_control, translation_control_grp], ihb = True, includeNetwork = True) pm.container(container, edit=True, publishAndBind=[translation_control + ".rotate", translation_control.stripNamespace() + "_rotate"]) pm.container(container, edit=True, publishAndBind=[translation_control + ".translate", translation_control.stripNamespace() + "_translate"]) return translation_control, translation_control_grp
def networkNode(self): self.meta_node = pm.createNode('network', n= self.userSpecifiedName + ':metaNode') pm.addAttr(self.meta_node, longName="ModuleType", dataType="string", keyable=False) pm.addAttr(self.meta_node, longName="Namespace", dataType="string", keyable=False) pm.addAttr(self.meta_node, longName="ModuleContainer", at="message") pm.addAttr(self.meta_node, longName="ModuleJoints", at="message", multi = True, indexMatters = True) pm.addAttr(self.meta_node, longName="MirrorModule", dataType="string", keyable=False) pm.addAttr(self.meta_node, longName="ParentObject", at="message") pm.addAttr(self.meta_node, longName="ModuleNodes", at="message", multi = True) # connect container meta node pm.addAttr(self.module_container, longName="MetaNode", at="message") self.meta_node.ModuleContainer.connect(self.module_container.MetaNode) # set module type to name of module.py self.meta_node.ModuleType.set(self.mod_moduleType, type = "string", lock = True) # set module name to name of module self.meta_node.Namespace.set(self.userSpecifiedName, type = "string", lock = True) utils.addNodeToContainer(self.module_container, self.meta_node, ihb = True, includeNetwork = True) return self.meta_node
def initializeParentModuleSetup(self, rootTranslationControl): """ Every module's root translation control will have a set of two joints. The parent object will equal to the unhookTarget_locator if it is not parented to another module. If it is parented to another module, the parent_object will be that modules translation control """ # setup root locator at rootTranslationControl as unHookTarget unhookTarget_locator = pm.spaceLocator(name = self.userSpecifiedName + ":unhookTarget_loc") pm.addAttr(unhookTarget_locator, longName="ParentObject", at="message") unhookTarget_locator.visibility.set(0) # set offset slightly off so we don't divide by a zero pm.pointConstraint(rootTranslationControl, unhookTarget_locator, offset = [0.001, 0.01, 0.001], name = self.userSpecifiedName + ":unhookTarget_locator_pointConstraint") if self.parent_object == None: self.parent_object = unhookTarget_locator pm.select(cl = True) # get the position of base target and the parent target # setup setup root joint at rootTranslationControl # setup endJoint to be at the location of the new hook object target_joint_position = pm.xform(self.parent_object, q = True, ws = True, translation = True) root_joint = pm.joint(name = self.userSpecifiedName + ":targetParent_root_joint", position = rootTranslationControl.translate.get()) target_joint = pm.joint(name = self.userSpecifiedName + ":target_end_joint", position = target_joint_position ) pm.joint(root_joint, edit=True, orientJoint="xyz", sao="yup") ik_nodes = self.stretchy_ik(root_joint, target_joint, container = self.module_container) target_locator = ik_nodes["end_locator"] doNotTouch_grp =ik_nodes["doNotTouch_grp"] # constrain the end parentJoint to the parent module pm.pointConstraint(rootTranslationControl, target_locator, maintainOffset=False, name = self.userSpecifiedName + ":targetObject_pointConstraint") # constrain the root parentJoint to the child module pm.pointConstraint(self.parent_object, root_joint, maintainOffset=False, name = self.userSpecifiedName + ":targetParent_pointConstraint") parent_group = pm.group([root_joint, unhookTarget_locator, doNotTouch_grp], name = self.userSpecifiedName + ":parent_group") utils.addNodeToContainer(self.module_container, [parent_group], ihb = True) for joint in [root_joint, target_joint]: joint.template.set(1) pm.container(self.module_container, edit=True, publishAndBind=[joint + ".rotate", joint.stripNamespace() + "_r"]) if self.parent_object != unhookTarget_locator: utils.setModuleMetaInfo(self.module_container, "ParentObject", self.findParentModule())
def install_joints(self): """ gathers information from the module and creates the joints """ # create list of joints joints = [] translation_controls = [] # clear selection pm.select(cl = True) # set current namespace to root. that way all namespaces will be child of the root only pm.namespace(setNamespace = ":") pm.namespace(add = self.userSpecifiedName) self.joints_grp = pm.group(empty = True, name = self.userSpecifiedName + ":joints_grp") self.misc_grp = pm.group(empty = True, name = self.userSpecifiedName + ":misc_grp") self.module_container = pm.container(name = self.userSpecifiedName + ":module_container" ) self.networkNode() # creating joints this way because when you select a joint and create a joint it will correct orientation index = 0 for joint in self.joint_info: joint_name = joint[0] joint_positions = joint[1] # if not the root joint, selecting the parent joint if index > 0: pm.select(joints[index-1], replace = True) # create joint and append to joints list new_joint = pm.PyNode(pm.joint(name = self.userSpecifiedName + ":" + joint_name, position = joint_positions) ) joints.append(new_joint) # if not the root joint, change the orient of the parent joint to defaults if index > 0: pm.joint(new_joint.getParent(), edit = True, orientJoint = "xyz", secondaryAxisOrient = "yup") pm.makeIdentity(new_joint, apply=True, translate=False, rotate=True, scale=False ) utils.addNodeToContainer(self.module_container, new_joint, ihb = True, includeNetwork = True) # Publish and bind rotation values for current joint to cointainer before locking; # this is important for later use with IK system setup to be able to rotate the joints attributes. pm.container(self.module_container, edit=True, publishAndBind=[new_joint + ".rotate", joint_name + "_r"]) pm.container(self.module_container, edit=True, publishAndBind=[new_joint + ".rotateOrder", joint_name + "_rotateOrder"]) pm.addAttr(new_joint, longName = "Meta", at="message") self.meta_node.ModuleJoints[index].connect(new_joint.Meta) index += 1 ''' mirrorBehavior = True mirrorXY = False mirrorYZ = False mirrorXZ = False pm.mirrorJoint(joints[0], mirrorBehavior = mirrorBehavior, mirrorXY = mirrorXY, mirrorYZ = mirrorYZ, mirrorXZ = mirrorXZ) ''' joints[0].setParent(self.joints_grp) joints[0].visibility.set(True) # TEMP- TURNING ON LOCAL AXIS for joint in joints: joint.displayLocalAxis.set(1) joint.template.set(1) # ------------------------------------------------------------------------- # # set up controls for the module module_control = controls.loadModuleControl(joints[0], self.userSpecifiedName, self.module_container) # install translation controls to each joint and parent it under the module control for joint in joints: #translation_controls[joint] = controls.loadTranslationControl(joint, self.userSpecifiedName, module_control) translation_controls.append(controls.loadTranslationControl(joint, self.userSpecifiedName,self.module_container, module_control) ) # point constraint root control to root joint pm.pointConstraint(translation_controls[0][0], joints[0], maintainOffset = False, name = self.userSpecifiedName + ":" + joints[0].stripNamespace() + "_rootTransContConstraint") self.initializeParentModuleSetup(translation_controls[0][0]) # ------------------------------------------------------------------------- # # set up stretch joint segments for index in range(len(joints) -1 ): # load joint rep onto joins # setup stretchy joint segments setupStretchyJointSegment = self.setupStretchyJointSegment(joints[index], joints[index + 1]) setupStretchyJointSegment[0].setParent(self.misc_grp) setupStretchyJointSegment[1].setParent(self.joints_grp) # ------------------------------------------------------------------------- # # parent items #module_control_grp.setParent(self.module_container) utils.addNodeToContainer(self.module_container, [self.misc_grp, self.joints_grp, module_control], ihb = True, includeNetwork = True) # don't know why, but cannot full delete the transform node pm.container(self.module_container, edit=True, publishAndBind=[module_control + ".translate", module_control.stripNamespace() + "_translate"]) pm.container(self.module_container, edit=True, publishAndBind=[module_control + ".rotate", module_control.stripNamespace() + "_rotate"]) pm.container(self.module_container, edit=True, publishAndBind=[module_control + ".scale", module_control.stripNamespace() + "_globalScale"]) # add meta information if self.module_container.hasAttr("MetaNode") == True: for node in pm.container(self.module_container, q = True, nodeList = True): if node.nodeType() != "network" or "joint": if not node.hasAttr("MetaNode"): pm.addAttr(node, longName="MetaNode", at="message") self.meta_node.ModuleNodes.connect(node.MetaNode) self.install_customAttributes() # ------------------------------------------------------------------------- # # lock nodes pm.lockNode(self.module_container, lock = True, lockUnpublished = True) pm.select(cl = True)
def stretchy_ik(self, root_joint, end_joint, container = None, poleVector_object = None): """ Creates basic stretchy IK """ root_joint = pm.PyNode(root_joint) end_joint = pm.PyNode(end_joint) module_namespace = root_joint.namespace() if poleVector_object != None: poleVector_object = pm.PyNode(poleVector_object) or poleVector_object or pm.ls(sl = True)[2] doNotTouch_grp = pm.group(empty = True, name = module_namespace + root_joint.stripNamespace() + "_doNotTouchGrp") return_nodes = {} child_joints = [] utility_nodes = [] total_orig_length = 0.0 done = False parent = root_joint while not done: # get the child of the parent joint child = parent.getChildren()[0] child_joints.append(child) # get the translateX of the child joint and add the translateX to total_orig_length total_orig_length += fabs(child.translateX.get() ) # parent joint is now equal to the child joint parent = child # if the child joint is equal to the end joint, loops ends if parent == end_joint: done = True ## create and rename all IK handle related objects ikHandle, ikEffector = pm.ikHandle(name = module_namespace + root_joint.stripNamespace() + "_ikHandle", sj = root_joint, ee = end_joint, solver = "ikRPsolver") pm.rename(ikEffector, end_joint + "_effector") # if no poleVector object is given, a space locator is created above the root locator if poleVector_object == None: poleVector_object = pm.spaceLocator(n = ikHandle + '_poleVectorLocator') poleVector_object.visibility.set(0) pm.delete(pm.parentConstraint(root_joint, poleVector_object, maintainOffset = False)) doNotTouch_grp.addChild(poleVector_object) pm.poleVectorConstraint(poleVector_object, ikHandle, name = ikHandle + '_poleVectorLocator') ## create locators at root joint and end joint root_locator = pm.spaceLocator(name = module_namespace + root_joint.stripNamespace() + "_rootLoc") pm.pointConstraint(root_joint, root_locator, maintainOffset = False, n = module_namespace + "_" + root_locator + "_pointConstraint") end_locator = pm.spaceLocator(name = module_namespace + end_joint.stripNamespace() + "_endLoc") pm.xform(end_locator, ws = True, translation = (pm.xform(end_joint, q = True, ws = True, translation = True) ) ) pm.pointConstraint(end_locator, ikHandle, maintainOffset = False, n = module_namespace + end_joint.stripNamespace() + "_pointConstraint") ## add distance between node distance_node = pm.shadingNode("distanceBetween", asUtility = True, name =module_namespace + root_joint.stripNamespace() + "distanceBetween_node") root_locator.getShape().worldPosition.connect(distance_node.point1) end_locator.getShape().worldPosition.connect(distance_node.point2) # the scale factor node determines how much to multiply it against the joint length to get the stretch # setup the scale factor node scaleFactor_node = pm.shadingNode("multiplyDivide", asUtility = True, name = module_namespace + root_joint.stripNamespace() + "_scaleFactor_node") # set operation to divide scaleFactor_node.operation.set(2) scaleFactor_node.input2X.set(total_orig_length) distance_node.distance.connect(scaleFactor_node.input1X) utility_nodes.append(scaleFactor_node) if len(child_joints) == 1: for joint in child_joints: # multiply factor node takes the scale factor and multiplies it with original joint length tmp_multiplyFactor_node = pm.shadingNode("multiplyDivide", asUtility = True, name = module_namespace + root_joint.stripNamespace() + "_multiplyFactor_node") # set node input1X to translateX of joint tmp_multiplyFactor_node.input1X.set(joint.translateX.get() ) scaleFactor_node.outputX.connect(tmp_multiplyFactor_node.input2X) tmp_multiplyFactor_node.outputX.connect(joint.translateX) utility_nodes.append(tmp_multiplyFactor_node) for node in [root_locator, end_locator, ikHandle]: node.visibility.set(0) doNotTouch_grp.addChild(node) if container != None: utils.addNodeToContainer(container, doNotTouch_grp, ihb = True, includeNetwork = True) return_nodes["ikHandle"] = ikHandle return_nodes["ikEffector"] = ikEffector return_nodes["root_locator"] = root_locator return_nodes["end_locator"] = end_locator return_nodes["poleVector_object"] = poleVector_object return_nodes["doNotTouch_grp"] = doNotTouch_grp return_nodes["distance_node"] = distance_node return_nodes["utility_node"] = utility_nodes return return_nodes