def sqCreateStikyLipsDeformers(self, *args): baseMesh = None mainCurveList = [self.mainCurveA, self.mainCurveB] for mainCurve in mainCurveList: if baseMesh == None: baseMesh = cmds.duplicate(self.receptList[0], name=self.receptList[0]+"Base")[0] cmds.setAttr(baseMesh+".visibility", 0) wrapNode = cmds.deformer(mainCurve, name="StickyLips_Wrap", type="wrap")[0] try: cmds.connectAttr(self.receptList[0]+".dropoff", wrapNode+".dropoff[0]", force=True) cmds.connectAttr(self.receptList[0]+".inflType", wrapNode+".inflType[0]", force=True) cmds.connectAttr(self.receptList[0]+".smoothness", wrapNode+".smoothness[0]", force=True) cmds.connectAttr(self.receptList[0]+"Shape.worldMesh[0]", wrapNode+".driverPoints[0]", force=True) except: pass cmds.connectAttr(baseMesh+"Shape.worldMesh[0]", wrapNode+".basePoints[0]", force=True) cmds.connectAttr(mainCurve+"Shape.worldMatrix[0]", wrapNode+".geomMatrix", force=True) cmds.setAttr(wrapNode+".maxDistance", 1) cmds.setAttr(wrapNode+".autoWeightThreshold", 1) cmds.setAttr(wrapNode+".exclusiveBind", 1) baseCurveList = [self.baseCurveA, self.baseCurveB] for c, baseCurve in enumerate(baseCurveList): wireNode = cmds.wire(self.receptList[1], name=baseCurve+"_Wire", groupWithBase=False, crossingEffect=0, localInfluence=0)[0] cmds.connectAttr(mainCurveList[c]+"Shape.worldSpace[0]", wireNode+".baseWire[0]", force=True) cmds.connectAttr(baseCurve+"Shape.worldSpace[0]", wireNode+".deformedWire[0]", force=True) self.wireNodeList.append(wireNode) wireLocList = [] for i in range(0, self.maxIter): wireLocList.append(baseCurve+".u["+str(i)+"]") cmds.dropoffLocator(1, 1, wireNode, wireLocList)
def sqCreateStikyLipsDeformers(self, *args): baseMesh = None mainCurveList = [self.mainCurveA, self.mainCurveB] for mainCurve in mainCurveList: if baseMesh == None: baseMesh = cmds.duplicate(self.receptList[0], name=self.receptList[0] + "Base")[0] cmds.setAttr(baseMesh + ".visibility", 0) wrapNode = cmds.deformer(mainCurve, name="StickyLips_Wrap", type="wrap")[0] try: cmds.connectAttr(self.receptList[0] + ".dropoff", wrapNode + ".dropoff[0]", force=True) cmds.connectAttr(self.receptList[0] + ".inflType", wrapNode + ".inflType[0]", force=True) cmds.connectAttr(self.receptList[0] + ".smoothness", wrapNode + ".smoothness[0]", force=True) cmds.connectAttr(self.receptList[0] + "Shape.worldMesh[0]", wrapNode + ".driverPoints[0]", force=True) except: pass cmds.connectAttr(baseMesh + "Shape.worldMesh[0]", wrapNode + ".basePoints[0]", force=True) cmds.connectAttr(mainCurve + "Shape.worldMatrix[0]", wrapNode + ".geomMatrix", force=True) cmds.setAttr(wrapNode + ".maxDistance", 1) cmds.setAttr(wrapNode + ".autoWeightThreshold", 1) cmds.setAttr(wrapNode + ".exclusiveBind", 1) baseCurveList = [self.baseCurveA, self.baseCurveB] for c, baseCurve in enumerate(baseCurveList): wireNode = cmds.wire(self.receptList[1], name=baseCurve + "_Wire", groupWithBase=False, crossingEffect=0, localInfluence=0)[0] cmds.connectAttr(mainCurveList[c] + "Shape.worldSpace[0]", wireNode + ".baseWire[0]", force=True) cmds.connectAttr(baseCurve + "Shape.worldSpace[0]", wireNode + ".deformedWire[0]", force=True) self.wireNodeList.append(wireNode) wireLocList = [] for i in range(0, self.maxIter): wireLocList.append(baseCurve + ".u[" + str(i) + "]") cmds.dropoffLocator(1, 1, wireNode, wireLocList)
def rebuild(self): """ Rebuild the wire deformer from the recorded deformerData """ # ========== # - Checks - # ========== # Check Data for influence in self._influenceData.iterkeys(): # Check Wire Curve if not cmds.objExists(influence): print('Wire curve "' + influence + '" does not exist! Curve will not be added to deformer!') # Check Base Curves baseCurve = self._influenceData[influence]['influenceBase'] if not cmds.objExists(baseCurve): print( 'Wire curve base "' + baseCurve + '" does not exist! A static base curve will be generated from the deforming wire curve!') # Check Dropoff Locators for locator in self._locatorData.iterkeys(): if cmds.objExists(locator): cmds.delete(cmds.listRelatives(locator, p=True)[0]) # ==================== # - Rebuild Deformer - # ==================== result = super(WireData, self).rebuild() wireDeformer = result['deformer'] # ======================= # - Connect Wire Curves - # ======================= for influence in self._influenceData.iterkeys(): # Get current wire curve pair wireCurve = influence infIndex = self._influenceData[influence]['index'] baseCurve = self._influenceData[influence]['influenceBase'] # Connect deformed wire if not cmds.objExists(influence): continue cmds.connectAttr(wireCurve + '.worldSpace[0]', wireDeformer + '.deformedWire[' + str(infIndex) + ']', f=True) # Connect base wire if not cmds.objExists(baseCurve): baseCurve = cmds.duplicate(influence, n=baseCurve)[0] cmds.connectAttr(baseCurve + '.worldSpace[0]', wireDeformer + '.baseWire[' + str(infIndex) + ']', f=True) cmds.setAttr(baseCurve + '.v', 0) # Set Influence Attributes if cmds.getAttr(wireDeformer + '.dropoffDistance[' + str(infIndex) + ']', se=True): cmds.setAttr(wireDeformer + '.dropoffDistance[' + str(infIndex) + ']', self._influenceData[influence]['dropoffDist']) if cmds.getAttr(wireDeformer + '.scale[' + str(infIndex) + ']', se=True): cmds.setAttr(wireDeformer + '.scale[' + str(infIndex) + ']', self._influenceData[influence]['scale']) # ============================ # - Rebuild Dropoff Locators - # ============================ for locator in self._locatorData.iterkeys(): # Get data parent = self._locatorData[locator]['parent'] param = self._locatorData[locator]['parameter'] env = self._locatorData[locator]['envelope'] percent = self._locatorData[locator]['percent'] twist = self._locatorData[locator]['twist'] # Create Locator loc = cmds.dropoffLocator(env, percent, wire, parent + '.u[' + str(param) + ']')[0] # Apply Twist locConn = cmds.listConnections(loc + '.param', s=False, d=True, p=True)[0] locConnIndex = locConn.split('[')[-1].split(']')[0] cmds.setAttr(wireDeformer + '.wireLocatorTwist[' + str(locConnIndex) + ']', twist) # ================= # - Return Result - # ================= self.result['influence'] = self._influenceData.keys() self.result['dropoffLocator'] = self._locatorData.keys() return self.result
def dropoffLocator(*args, **kwargs): res = cmds.dropoffLocator(*args, **kwargs) if not kwargs.get('query', kwargs.get('q', False)): res = _factories.maybeConvert(res, _general.PyNode) return res
cmds.delete(cmds.orientConstraint(startLoc, sPlane)) cmds.delete(sPlane, constructionHistory=True) sCurve = cmds.curve(degree=1, point=[startPoint, endPoint]) sCurve = cmds.rename( sCurve, un + 'stretchCurve' ) # If named at the creation time, the shape node doesn't get renamed cmds.parent(startLoc, endLoc, sPlane[0], sCurve, sGrp) # create wire deformer and dropoffLocator for twisting sWire = cmds.wire(sPlane[0], wire=sCurve, name=un + 'stretchWire') cmds.wire(sWire[1], edit=True, dropoffDistance=[(0, 20), (1, 20)]) cmds.select(sWire[1] + '.u[0]', r=True) cmds.dropoffLocator(1.0, 1.0, sWire[0]) cmds.select(sWire[1] + '.u[1]', r=True) cmds.dropoffLocator(1.0, 1.0, sWire[0]) # skin wire to bone driver, connect rotation of locators to drop off locators twist cmds.connectAttr(startLoc[0] + '.rotateX', sWire[0] + '.wireLocatorTwist[0]') cmds.connectAttr(endLoc[0] + '.rotateX', sWire[0] + '.wireLocatorTwist[1]') cmds.skinCluster(startWJoint, endWJoint, sWire[1], maximumInfluences=1, toSelectedBones=True) # crating follicles on sPlane and joints
def make_stretch_plane(prefix='', start_joint=cmds.ls(selection=True)[0], end_joint=cmds.listRelatives(start_joint)[0], number_of_bones=3, stretch_len=cmds.getAttr(end_joint + '.translateX')): """ :param prefix: str, name of objects :param start_joint: str, start point of stretch plane and parent bone :param end_joint: str, end point of stretch plane (right now its just the child of the start joint) :param number_of_bones: float, how many bones will be placed along the length of the plane :param stretch_len: float, the length of the plane, from start joint to end joint :return: list[], containing all stretch joints for skinning """ # TODO need to get actual distance between points for spine start_point = cmds.xform(start_joint, query=True, worldSpace=True, translation=True) end_point = cmds.xform(end_joint, query=True, worldSpace=True, translation=True) # create start + end locators, bones to skin the wire to, and an empty group start_loc = cmds.spaceLocator(name='start_loc') cmds.parent(start_loc, start_joint, relative=True) end_loc = cmds.spaceLocator(name='end_loc') cmds.parent(end_loc, end_joint, relative=True) start_w_joint = cmds.joint(name='startWireJoint') cmds.parent(start_w_joint, start_loc) end_w_joint = cmds.joint(name='endWireJoint') cmds.parent(end_w_joint, end_loc) s_grp = cmds.group(empty=True, name=prefix + 'stretchPlaneGrp') cmds.delete(cmds.parentConstraint(start_loc, s_grp)) # create NURBS plane and CV curve. Group everything into the new sGrp s_plane = cmds.nurbsPlane(name=prefix + 'stretchPlane', width=stretch_len, lengthRatio=.2, patchesU=number_of_bones, axis=(0, 1, 0)) s_plane_shape = cmds.listRelatives(s_plane, shapes=True)[0] cmds.delete(cmds.parentConstraint(start_loc, end_loc, s_plane)) cmds.delete(cmds.orientConstraint(start_loc, s_plane)) cmds.delete(s_plane, constructionHistory=True) s_curve = cmds.curve(degree=1, point=[start_point, end_point]) s_curve = cmds.rename( s_curve, prefix + 'stretchCurve' ) # If named at the creation time, the shape node doesn't get renamed cmds.parent(start_loc, end_loc, s_plane[0], s_curve, s_grp) # create wire deformer and dropoffLocator for twisting s_wire_deform = cmds.wire(s_plane[0], wire=s_curve, name=prefix + 'stretchWire')[0] cmds.wire(s_curve, edit=True, dropoffDistance=[(0, 20), (1, 20)]) cmds.select(s_curve + '.u[0]', r=True) cmds.dropoffLocator(1.0, 1.0, s_wire_deform) cmds.select(s_curve + '.u[1]', r=True) cmds.dropoffLocator(1.0, 1.0, s_wire_deform) # connect rotation of locators to drop off locators twist, skin wire to bone driver cmds.connectAttr(start_loc[0] + '.rotateX', s_wire_deform + '.wireLocatorTwist[0]') cmds.connectAttr(end_loc[0] + '.rotateZ', s_wire_deform + '.wireLocatorTwist[1]') cmds.skinCluster(start_w_joint, end_w_joint, s_curve, maximumInfluences=1, toSelectedBones=True) # crating follicles on sPlane and joints s_joints_collection = [] fol_grp = cmds.group(empty=True, name=prefix + 'follicleGrp') cmds.parent(fol_grp, s_grp) for x in range(number_of_bones): fol_shape = cmds.createNode("follicle") fol_trans = cmds.listRelatives(fol_shape, parent=True)[0] fol_trans = cmds.rename(fol_trans, prefix + "follicle_{:02d}".format(x + 1)) fol_shape = cmds.listRelatives(fol_trans, shapes=True)[0] fol_shape = cmds.rename(fol_shape, prefix + "follicleShape_{:02d}".format(x + 1)) cmds.connectAttr(s_plane_shape + '.worldMatrix[0]', fol_shape + '.inputWorldMatrix') cmds.connectAttr(s_plane_shape + '.local', fol_shape + '.inputSurface') cmds.connectAttr(fol_shape + '.outTranslate', fol_trans + '.translate') cmds.connectAttr(fol_shape + '.outRotate', fol_trans + '.rotate') v_position = (1.0 / (number_of_bones + 1)) * (x + 1) cmds.setAttr(fol_shape + '.parameterU', v_position) cmds.setAttr(fol_shape + '.parameterV', .5) # here I'm adding a joint, as the follicle is selected the joint is parented under it. # im also adding the joint to a list i can use later s_joints_collection.append( cmds.joint(name=prefix + "stretchJoint_{:02d}".format(x + 1))) cmds.parent(fol_trans, fol_grp) # creating nodes for stretching bones s_curve_shape = cmds.listRelatives(s_curve, shapes=True)[0] s_curve_info = cmds.createNode('curveInfo', name='SCurveInfo') cmds.rename(s_curve_info, 'SCurveInfo') cmds.connectAttr(s_curve_shape + '.worldSpace[0]', s_curve_info + '.inputCurve') joint_scale = cmds.createNode('multiplyDivide', name='sJointScale') cmds.setAttr(joint_scale + '.operation', 2) cmds.setAttr(joint_scale + '.input2X', stretch_len) cmds.connectAttr(s_curve_info + '.arcLength', joint_scale + '.input1X') # connecting up nodes to bones for joint in s_joints_collection: cmds.connectAttr(joint_scale + '.outputX', joint + '.scaleX') # creating a variable for the base wire of the wire deformer s_base_wire = cmds.listConnections(s_wire_deform + ".baseWire", destination=False, source=True)[0] # creating group inorder to help organisation and prevent double transforms s_rig_grp = cmds.group(empty=True, name=prefix + 'stretchPlaneRigGrp') align(start_joint, s_rig_grp) cmds.parent(s_rig_grp, s_grp) cmds.parent(s_plane[0], s_base_wire, start_loc, end_loc, s_rig_grp) cmds.setAttr(start_w_joint + ".visibility", False) cmds.setAttr(end_w_joint + ".visibility", False) # Connecting end locators to driving joints -will have to do this properly in the main script cmds.pointConstraint(end_joint, end_loc) cmds.connectAttr( end_joint + '.rotateZ', end_loc[0] + '.rotateZ') # TODO: add if statment for elbow/wrist rotations cmds.parent(s_rig_grp, start_joint) return s_joints_collection
def createCtrlSys(crv, rootCrv, surface, rootSurface, name, parameter=0.5, iteration=1): # Get surface shape crv_shape = cmds.listRelatives(crv[0], type="shape")[0] rootCrv_shape = cmds.listRelatives(rootCrv[0], type="shape")[0] surface_shape = cmds.listRelatives(surface[0], type="shape") rootSurface_shape = cmds.listRelatives(rootSurface[0], type="shape") # create wire, cluster wire = cmds.wire(surface, gw=False, en=1.0, ce=0.0, li=0.0, dds=(0, 1000), w=crv, n=name + "_wire")[0] newCluster = cmds.cluster(rootCrv[0] + '.cv[:]', n="{}_{}_FreeSys_Crv_Clst".format( name, iteration), envelope=1) # run dynamicClst script cmds.select(rootCrv[0], r=1) dynamicSys_data = tp_createDynamicClst() cmds.select(cl=1) # Get arc length rootCrv_arcLength = cmds.arclen(rootCrv) # Create control ctrl_data = bd_buildCtrl(ctrl_type="sphere", name="{}_{}".format(name, iteration), sufix="_FreeSys_Ctrl", offset=1) # Create follicle on surface follicle_data = createFollicle(inputSurface=rootSurface_shape, name=name + '_FreeSys_Ctrl_Flc', hide=0) # Point constraint ctrl grp cmds.pointConstraint(follicle_data[0], ctrl_data[1], offset=(0, 0, 0), weight=1) # Orient constroint ctrl cmds.orientConstraint(follicle_data[0], ctrl_data[0], mo=1, weight=1) # Create attributes on control - Division, Parameter, Twist, Interpotaion cmds.addAttr(ctrl_data[0], ln="customAttr", nn="________", at="enum", en="Custom:", keyable=True) cmds.setAttr(ctrl_data[0] + ".customAttr", lock=1) cmds.addAttr(ctrl_data[0], ln="parameter", nn="Parameter", at="double", min=0, max=rootCrv_arcLength, dv=(rootCrv_arcLength / 2), keyable=True) cmds.addAttr(ctrl_data[0], ln="twist", nn="Twist", at="double", min=-1000, max=1000, dv=0, keyable=True) cmds.addAttr(ctrl_data[0], ln="interpolation", nn="Interpolation", at="long", min=1, max=6, dv=4, keyable=True) cmds.connectAttr(ctrl_data[0] + ".interpolation", dynamicSys_data[0] + ".interpolation") # Create setRange for translate conversion 0 1 ctrl_setRange = cmds.shadingNode('setRange', au=1, n=name + '_ctrl_t_setRange') cmds.setAttr(ctrl_setRange + '.max.maxX', 1) cmds.setAttr(ctrl_setRange + '.oldMax.oldMaxX', rootCrv_arcLength) cmds.connectAttr(ctrl_data[0] + '.parameter', ctrl_setRange + '.value.valueX') # Connect ctrl translate x to follicle uVlue cmds.connectAttr(ctrl_setRange + '.outValue.outValueX', follicle_data[1] + '.parameterU') # Create set range for scale X, output max 0-1, control ramp falloff scale_setRange = cmds.shadingNode('setRange', au=1, n=name + '_ctrl_scaleToFalloff_setRange') cmds.setAttr(scale_setRange + '.oldMin.oldMinX', 0.2) cmds.setAttr(scale_setRange + '.oldMax.oldMaxX', 5) cmds.setAttr(scale_setRange + '.min.minX', 0.1) cmds.setAttr(scale_setRange + '.max.maxX', 1) cmds.connectAttr(ctrl_data[0] + '.scale.scaleX', scale_setRange + '.value.valueX') # Calcaulating start and end position colorStart_mpDiv = cmds.shadingNode('multiplyDivide', au=1, n=name + '_scaleInvert_mpDivide') colorStartEnd_plusMA = cmds.shadingNode('plusMinusAverage', au=1, n=name + '_falloffResult_plusMA') # Invert Scale newRange value cmds.setAttr(colorStart_mpDiv + '.input2.input2X', -1) cmds.connectAttr(scale_setRange + '.outValue.outValueX', colorStart_mpDiv + '.input1.input1X') # Connect to plusMinusAvarege node cmds.connectAttr(colorStart_mpDiv + '.output.outputX', colorStartEnd_plusMA + '.input2D[0].input2Dx') cmds.connectAttr(scale_setRange + '.outValue.outValueX', colorStartEnd_plusMA + '.input2D[0].input2Dy') cmds.connectAttr(ctrl_setRange + '.outValue.outValueX', colorStartEnd_plusMA + '.input2D[1].input2Dx') cmds.connectAttr(ctrl_setRange + '.outValue.outValueX', colorStartEnd_plusMA + '.input2D[1].input2Dy') # Create clamp setRange - Limiting calculation to 0 to 1 clamp_setRenge = cmds.shadingNode('setRange', au=1, n=name + '_resultClamp_setRange') cmds.setAttr(clamp_setRenge + '.oldMax.oldMaxX', 1) cmds.setAttr(clamp_setRenge + '.max.maxX', 1) cmds.setAttr(clamp_setRenge + '.oldMax.oldMaxY', 1) cmds.setAttr(clamp_setRenge + '.max.maxY', 1) cmds.connectAttr(colorStartEnd_plusMA + '.output2D.output2Dx', clamp_setRenge + '.value.valueX') cmds.connectAttr(colorStartEnd_plusMA + '.output2D.output2Dy', clamp_setRenge + '.value.valueY') # Connect to ramp colors # Connect and configure color 1 mid cmds.connectAttr(ctrl_setRange + '.outValue.outValueX', dynamicSys_data[0] + '.colorEntryList[0].position') cmds.setAttr(dynamicSys_data[0] + '.colorEntryList[0].color', 1, 1, 1, type="double3") # Connect and configure color 0 start cmds.connectAttr(clamp_setRenge + '.outValue.outValueX', dynamicSys_data[0] + '.colorEntryList[2].position') cmds.setAttr(dynamicSys_data[0] + '.colorEntryList[2].color', 0, 0, 0, type="double3") # Connect and configure color 2 end cmds.connectAttr(clamp_setRenge + '.outValue.outValueY', dynamicSys_data[0] + '.colorEntryList[1].position') cmds.setAttr(dynamicSys_data[0] + '.colorEntryList[1].color', 0, 0, 0, type="double3") # Connect ctrl to cluster cmds.connectAttr(ctrl_data[0] + '.translate', newCluster[1] + '.translate') # Create and connect dropoff locators cmds.select("{}.u[{}]".format(crv[0], 0), r=True) dropoffLoc1 = cmds.dropoffLocator(1.0, 1.0, wire)[0] cmds.select("{}.u[{}]".format(crv[0], 0.1), r=True) dropoffLoc2 = cmds.dropoffLocator(1.0, 1.0, wire)[0] cmds.select("{}.u[{}]".format(crv[0], 0.2), r=True) dropoffLoc3 = cmds.dropoffLocator(1.0, 1.0, wire)[0] cmds.select(cl=1) cmds.connectAttr(ctrl_data[0] + ".twist", "{}.wireLocatorTwist[{}]".format(wire, 1)) cmds.connectAttr(ctrl_setRange + '.outValue.outValueX', dropoffLoc2 + '.param') cmds.connectAttr(clamp_setRenge + '.outValue.outValueX', dropoffLoc1 + '.param') cmds.connectAttr(clamp_setRenge + '.outValue.outValueY', dropoffLoc3 + '.param') lock_hide([ctrl_data[0]], [".rx", ".ry", ".rz"]) # Set control parameter of choice ctrl_tergetPosition = rootCrv_arcLength * parameter cmds.setAttr(ctrl_data[0] + '.parameter', ctrl_tergetPosition) # Group everything or pass creations to master grouper return newCluster[1], ctrl_data[1], follicle_data[0], ctrl_data[0]
def createBaseCtrl(crv, surface, name, color1, color2): # Wire surface to curve wire = cmds.wire(surface, gw=False, en=1.0, ce=0.0, li=0.0, dds=(0, 100), w=crv, n=name + "_wire")[0] cmds.setAttr(wire + ".rotation", 0) # Create clusters from all cv's on curve and relative dynamic systems cluster_start = cmds.cluster(crv[0] + '.cv[:]', n=name + '_Start_Crv_Clst', envelope=1) cmds.select(crv[0], r=1) dynSys_start_data = tp_createDynamicClst() cluster_end = cmds.cluster(crv[0] + '.cv[:]', n=name + '_End_Crv_Clst', envelope=1) cmds.select(crv[0], r=1) dynSys_end_data = tp_createDynamicClst() # Adjust dynamic system ramp for start and end controls adjustRamp(dynSys_start_data[0], inPos=0, outPos=1, createMid=0, inColor=1, outColor=0) adjustRamp(dynSys_end_data[0], inPos=0, outPos=1, createMid=0, inColor=0, outColor=1) # Create controls - get resulting return data ctrl_start_data = bd_buildCtrl(ctrl_type="cube", scale=2, name=name + '_Start') setCtrlColor(ctrl_start_data[0], color=color1) ctrl_end_data = bd_buildCtrl(ctrl_type="cube", scale=2, name=name + '_End') setCtrlColor(ctrl_end_data[0], color=color2) # Get start and end point on curve positions # Position ctrl groups at start and end start_position = cmds.pointOnCurve(crv, pr=0, p=1) end_position = cmds.pointOnCurve(crv, pr=1, p=1) cmds.xform(ctrl_start_data[1], t=start_position) cmds.xform(ctrl_end_data[1], t=end_position) # Connect controls to clusters # Leaving X rotation out - Will be controlled by wire dropoff locators cmds.connectAttr(ctrl_start_data[0] + '.translate', cluster_start[1] + '.translate') cmds.connectAttr(ctrl_start_data[0] + '.rotate.rotateY', cluster_start[1] + '.rotate.rotateY') cmds.connectAttr(ctrl_start_data[0] + '.rotate.rotateZ', cluster_start[1] + '.rotate.rotateZ') cmds.connectAttr(ctrl_end_data[0] + '.translate', cluster_end[1] + '.translate') cmds.connectAttr(ctrl_end_data[0] + '.rotate.rotateY', cluster_end[1] + '.rotate.rotateY') cmds.connectAttr(ctrl_end_data[0] + '.rotate.rotateZ', cluster_end[1] + '.rotate.rotateZ') # Add interpolation control attribute to start/end control cmds.addAttr(ctrl_start_data[0], ln="customAttr", nn="________", at="enum", en="Custom:", keyable=True) cmds.setAttr(ctrl_start_data[0] + ".customAttr", lock=1) cmds.addAttr(ctrl_start_data[0], ln="interpolation", nn="Interpolation", at="long", min=1, max=6, dv=1, keyable=True) cmds.connectAttr(ctrl_start_data[0] + ".interpolation", dynSys_start_data[0] + ".interpolation") cmds.addAttr(ctrl_end_data[0], ln="customAttr", nn="________", at="enum", en="Custom:", keyable=True) cmds.setAttr(ctrl_end_data[0] + ".customAttr", lock=1) cmds.addAttr(ctrl_end_data[0], ln="interpolation", nn="Interpolation", at="long", min=1, max=6, dv=1, keyable=True) cmds.connectAttr(ctrl_end_data[0] + ".interpolation", dynSys_end_data[0] + ".interpolation") # Ends rotation control # Create dropoff locators - start end # Connect to controls rotation cmds.select("{}.u[{}]".format(crv[0], 0), r=True) dropoffLoc_start = cmds.dropoffLocator(1.0, 1.0, wire)[0] cmds.connectAttr(ctrl_start_data[0] + ".rx", "{}.wireLocatorTwist[{}]".format(wire, 0)) cmds.select("{}.u[{}]".format(crv[0], 1), r=True) dropoffLoc_end = cmds.dropoffLocator(1.0, 1.0, wire)[0] cmds.connectAttr(ctrl_end_data[0] + ".rx", "{}.wireLocatorTwist[{}]".format(wire, 1)) # return [0] ctrl 1 transform, [1] ctrl 1 grp, [2] ctrl 2 transform, [3] ctrl 2 grps, [4] cluster 1, [5] cluster 2 return ctrl_start_data[0], ctrl_start_data[1], ctrl_end_data[ 0], ctrl_end_data[1], cluster_start, cluster_end
def ribbonize(surf_tr, equal=1, num_of_ctrls=5, num_of_jnts=29, prefix="", constrain=1, add_fk=0, wire=0): attrs = [ ".tx", ".ty", ".tz", ".rx", ".ry", ".rz", ".sx", ".sy", ".sz", ".v" ] if prefix == "": mc.warning("te importa nombrarlo?") return else: prefix = prefix + "_" ##################################################### surf_tr = mc.rename(surf_tr, prefix + "ribbon_surface") surf = mc.listRelatives(surf_tr, shapes=True)[0] # Congelar transformaciones y borrar el historial de superficies. mc.makeIdentity(surf_tr, t=True, r=True, s=True, apply=True) mc.delete(surf_tr, ch=True) # duplicar la superficie curvas para determinar la direccion. u_curve = mc.duplicateCurve(surf_tr + ".v[.5]", local=True, ch=0) v_curve = mc.duplicateCurve(surf_tr + ".u[.5]", local=True, ch=0) # borro historial solo porsiaca. mc.delete(surf_tr, ch=True) u_length = mc.arclen(u_curve) v_length = mc.arclen(v_curve) if u_length < v_length: mc.reverseSurface(surf_tr, d=3, ch=False, rpo=True) mc.reverseSurface(surf_tr, d=0, ch=False, rpo=True) parameter = ".parameterU" other_param = ".parameterV" # corrija u_curve despues de invertir para calcular la longitud. u_curve_corr = mc.duplicateCurve(surf_tr + ".v[.5]", local=True, ch=0)[0] ############################################################################# # La superficie seleccionada es periodica o abierta? (cilindro o plano) if mc.getAttr(surf + ".formU") == 2 or mc.getAttr(surf + ".formV") == 2: curve_type = "periodic" divider_for_ctrls = num_of_ctrls elif mc.getAttr(surf + ".formU") == 0 or mc.getAttr(surf + ".formV") == 0: curve_type = "open" divider_for_ctrls = num_of_ctrls - 1 ############################################################################# param_ctrls = param_from_length(u_curve_corr, num_of_ctrls, curve_type, "uv") param_joints = param_from_length(u_curve_corr, num_of_jnts, curve_type, "uv") length = mc.arclen(u_curve_corr) mc.delete(u_curve, v_curve, u_curve_corr) ############################################################################ # Creo grupos, Control General y control general de offset final_group = mc.group(n=prefix + "ribbon_grp", em=True) ctrl_joints_grp = mc.group(n=prefix + "ctrl_joints_grp", em=True) ctrl_grp = mc.group(n=prefix + "ctrls_grp", em=True) follicles_grp = mc.group(n=prefix + "follicles_grp", em=True) rig_grp = mc.group(n=prefix + "rig_grp", em=True) main_ctrl = mc.circle(n=prefix + "ctrl_main", nr=(0, 1, 0), r=length / 5, ch=0)[0] main_ctrl_offset = mc.group(n=prefix + "ctrl_main_offset", em=True) mc.parent(main_ctrl, main_ctrl_offset) mc.parent(ctrl_grp, main_ctrl) mc.parent(main_ctrl_offset, rig_grp, final_group) mc.parent(surf_tr, ctrl_joints_grp, follicles_grp, rig_grp) # Muevo main_ctrl_offset al centro de la geometria bbox (en caso de que el pivote este en otro lugar) mid_point = get_bbox_center(surf_tr) for attr, mid_pnt_el in izip(attrs[:3], mid_point): mc.setAttr(main_ctrl_offset + attr, mid_pnt_el) ############################################################################ fols = [] fols_tr = [] bind_jnts = [] bnd_joints_rad = (length / 60) / (float(num_of_jnts) / 40) for x in range(num_of_jnts): fol = mc.createNode("follicle") mc.setAttr(fol + ".visibility", 0) temp_fol = mc.listRelatives(fol, p=True)[0] fols_tr.append( mc.rename(temp_fol, "{}follicle_{:02d}".format(prefix, x + 1))) fols.append(mc.listRelatives(fols_tr[-1], s=True)[0]) # conecto follicle shapes al transform mc.connectAttr(fols[-1] + ".outTranslate", fols_tr[-1] + ".translate", f=True) mc.connectAttr(fols[-1] + ".outRotate", fols_tr[-1] + ".rotate", f=True) # atacho follicle shapes a la superficie mc.connectAttr(surf + ".worldMatrix[0]", fols[-1] + ".inputWorldMatrix") mc.connectAttr(surf + ".local", fols[-1] + ".inputSurface") mc.setAttr(fols[-1] + parameter, param_joints[x]) mc.setAttr(fols[-1] + other_param, 0.5) mc.parent(fols_tr[-1], follicles_grp) # creo el bind final y joints en la superficie bind_jnts.append( mc.createNode("joint", n="{}bnd_jnt_{:02d}".format(prefix, x + 1))) mc.parent(bind_jnts[-1], fols_tr[-1], r=True) mc.setAttr(bind_jnts[-1] + ".radius", bnd_joints_rad) set_color(bind_jnts, "mid_blue") #creo un temporal follicles para controles offset groups para alinear temp_fols = [] temp_fols_tr = [] for x in range(num_of_ctrls): temp_fols.append(mc.createNode("follicle")) temp_fols_tr.append(mc.listRelatives(temp_fols[-1], p=True)[0]) mc.connectAttr(temp_fols[-1] + ".outTranslate", temp_fols_tr[-1] + ".translate", f=True) mc.connectAttr(temp_fols[-1] + ".outRotate", temp_fols_tr[-1] + ".rotate", f=True) mc.connectAttr(surf + ".worldMatrix[0]", temp_fols[-1] + ".inputWorldMatrix") mc.connectAttr(surf + ".local", temp_fols[-1] + ".inputSurface") #################################################### if equal == 1: for x, temp_fol in enumerate(temp_fols): mc.setAttr(temp_fol + parameter, param_ctrls[x]) mc.setAttr(temp_fol + other_param, 0.5) if equal == 0: v = 0 for temp_fol in temp_fols: mc.setAttr(temp_fol + parameter, v) mc.setAttr(temp_fol + other_param, 0.5) v = v + (1.0 / divider_for_ctrls) #################################################### #creo controles y controle para joints controls = ctrl_maker(prefix, ctrl_type="cube", count=num_of_ctrls, deg=3, sp=8) ctrl_ofs_grps = [] ctrl_joints = [] ctrl_jnt_ofs_grps = [] ctrl_joints_rad = bnd_joints_rad * 2 ik_ctrl_scale = (length / 35) / (float(num_of_ctrls) / 5) for x, ctrl in enumerate(controls): ctrl_ofs_grp = mc.group(ctrl, n="{}_offset".format(ctrl)) mc.delete(mc.parentConstraint(temp_fols_tr[x], ctrl_ofs_grp)) ctrl_ofs_grps.append(ctrl_ofs_grp) #escala ik controls ctrl_shapes = mc.listRelatives(ctrl, s=True) for ctrl_shape in ctrl_shapes: ctrl_cvs_count = mc.getAttr(ctrl_shape + ".controlPoints", size=True) mc.scale(ik_ctrl_scale, ik_ctrl_scale, ik_ctrl_scale, "{}.cv[0:{}]".format(ctrl_shape, ctrl_cvs_count - 1), r=True, ocp=True) #creo los controles de joints ctrl_joints.append( mc.createNode("joint", n="{}ctrl_jnt_{:02d}".format(prefix, x + 1))) #seteo el radio de controles para joints de 2 tiepos. de el surface y joints mc.setAttr(ctrl_joints[x] + ".radius", ctrl_joints_rad) #creo offset groups para cotroles de joints ctrl_jnt_ofs_grp = mc.group(ctrl_joints[-1], n="{}_offset".format(ctrl_joints[-1])) mc.delete(mc.parentConstraint(temp_fols_tr[x], ctrl_jnt_ofs_grp)) ctrl_jnt_ofs_grps.append(ctrl_jnt_ofs_grp) ### set_color(controls, "green") set_color(ctrl_joints, "red") mc.parent(ctrl_ofs_grps, ctrl_grp) mc.parent(ctrl_jnt_ofs_grps, ctrl_joints_grp) lock_hide(ctrl_ofs_grps, attrs[:9]) lock_hide(ctrl_jnt_ofs_grps, attrs[:9]) mc.delete(temp_fols_tr) #################################################### #determino que constraint o coneccion o metodo es elegido# que formalidad if constrain == 0: for (c, j) in izip(controls, ctrl_joints): for attr in attrs[:7]: #skip de la escala de atributos mc.connectAttr(c + attr, j + attr) mc.parentConstraint(main_ctrl, ctrl_joints_grp, mo=True) mc.scaleConstraint(main_ctrl, ctrl_joints_grp) #escala del foliculo con el main // por coneccion del editor for flt in fols_tr: mc.connectAttr(main_ctrl + ".sx", flt + ".sx") mc.connectAttr(main_ctrl + ".sx", flt + ".sy") mc.connectAttr(main_ctrl + ".sx", flt + ".sz") elif constrain == 1: for (c, j) in izip(controls, ctrl_joints): mc.parentConstraint(c, j) mc.scaleConstraint(c, j) #scala del folliculos con el main control for flt in fols_tr: mc.scaleConstraint(main_ctrl, flt) ####################################################################### if wire == True and num_of_ctrls > 1: temp_crv = mc.duplicateCurve(surf_tr + ".v[.5]", n=prefix + "wire_crv", local=False, ch=0)[0] if num_of_ctrls == 2: degree = 1 else: degree = 3 wire_crv = mc.curve(p=param_from_length( temp_crv, num_of_ctrls + (num_of_ctrls - 1), "open", "world"), d=degree) mc.delete(temp_crv) wire_crv = mc.rename( wire_crv, prefix + "wire_crv" ) # Si el nombre va en el momento de la creacion, la forma no se renombra mc.delete(wire_crv, ch=True) wire = mc.wire(surf_tr, gw=False, en=1.0, ce=0.0, li=0.0, dds=(0, 50), w=wire_crv, n=prefix + "wire")[0] mc.connectAttr(main_ctrl + ".sx", wire + ".scale[0]") cps = param_from_length(wire_crv, num_of_ctrls, "open", "uv", normalized=False) for cp in cps: mc.select("{}.u[{}]".format(wire_crv, cp), r=True) mc.dropoffLocator(1.0, 1.0, wire) mc.select(cl=True) for x, ctrl in enumerate(controls): mc.connectAttr(ctrl + ".rx", "{}.wireLocatorTwist[{}]".format(wire, x)) wire_grp = mc.group(wire_crv, wire_crv + "BaseWire", n=prefix + "wire_crv_grp") mc.parent(wire_grp, rig_grp) lock_hide([wire_grp], attrs[:9]) wire_skin_cluster = mc.skinCluster(ctrl_joints, wire_crv, dr=2, mi=2, bm=0)[0] else: #bind de la superficie a los joints nurbs_skin_cluster = mc.skinCluster(ctrl_joints, surf_tr, dr=2, mi=num_of_ctrls - 1, ns=num_of_ctrls * 5, bm=0, n=prefix + "skinCluster")[0] mc.skinPercent(nurbs_skin_cluster, surf_tr, pruneWeights=0.2) if wire == True and num_of_ctrls == 1: mc.warning("wire skipped. at least 2 controls needed") ########################################################################################## mc.setAttr(surf_tr + ".v", 0) mc.setAttr(rig_grp + ".v", 0) mc.connectAttr(main_ctrl + ".sx", main_ctrl + ".sy") mc.connectAttr(main_ctrl + ".sx", main_ctrl + ".sz") mc.aliasAttr("Scale", main_ctrl + ".sx") set_color(main_ctrl, "yellow") mc.connectAttr(main_ctrl_offset + ".sx", main_ctrl_offset + ".sy") mc.connectAttr(main_ctrl_offset + ".sx", main_ctrl_offset + ".sz") mc.aliasAttr("Scale", main_ctrl_offset + ".sx") #lock and hide atributos lock_hide([ final_group, follicles_grp, ctrl_joints_grp, surf_tr, ctrl_grp, rig_grp ], attrs[:9]) lock_hide([ctrl_grp, main_ctrl, main_ctrl_offset], attrs[7:]) lock_hide(controls, attrs[7:]) #limpiamos seleccion (clear selection) mc.select( cl=True ) #Si la seleccion no se borra, se agrega un bind de control al conjunto de bind de enlace #crea a set con bind joints bind_jnts_set = mc.sets(n=prefix + "bind_jnts_set") mc.sets(bind_jnts, add=bind_jnts_set) mc.select(cl=True) ik_ctrls_set = mc.sets(n=prefix + "ik_ctrls_set") mc.sets(controls, add=ik_ctrls_set) mc.select(cl=True) controls_set = mc.sets(n=prefix + "controls_set") mc.sets(main_ctrl, ik_ctrls_set, add=controls_set) ########################################################################################## if add_fk == 1 and mc.getAttr(surf + ".formU") != 2 and mc.getAttr( surf + ".formV") != 2: fk_ctrls, fk_ctrl_off_grps = make_fk_ctrls(prefix, num_of_ctrls) mc.parent(fk_ctrl_off_grps[0], ctrl_grp) #scala fk controls fk_ctrl_scale = ik_ctrl_scale * 2 for fk_ctrl in fk_ctrls: fk_ctrl_shapes = mc.listRelatives(fk_ctrl, s=True) for fk_ctrl_shape in fk_ctrl_shapes: fk_ctrl_cvs_count = mc.getAttr(fk_ctrl_shape + ".controlPoints", size=True) mc.scale(fk_ctrl_scale, fk_ctrl_scale, fk_ctrl_scale, "{}.cv[0:{}]".format(fk_ctrl_shape, fk_ctrl_cvs_count - 1), r=True, ocp=True) #add fk controls al set mc.select(cl=True) fk_ctrls_set = mc.sets(n=prefix + "fk_ctrls_set") mc.sets(fk_ctrls, add=fk_ctrls_set) ######## ik_ctrl_constr_grps = [ mc.group(ctrl, n=ctrl + "_constr_grp") for ctrl in controls ] [ mc.xform(ik_ctrl_constr_grp, piv=(0, 0, 0), os=True) for ik_ctrl_constr_grp in ik_ctrl_constr_grps ] for ik, fk in izip(controls[:-1], fk_ctrl_off_grps): mc.delete(mc.parentConstraint(ik, fk)) for fk, ik in izip(fk_ctrls, ik_ctrl_constr_grps[:-1]): mc.parentConstraint(fk, ik) #constrain ultimo ik ctrl mc.parentConstraint(fk_ctrls[-1], ik_ctrl_constr_grps[-1], mo=True) lock_hide(ik_ctrl_constr_grps, attrs[:9]) ######## set_color(fk_ctrls, "blue") lock_hide(fk_ctrl_off_grps, attrs[:9]) mc.sets(fk_ctrls_set, add=controls_set) mc.select(cl=True) elif add_fk == 1 and (mc.getAttr(surf + ".formU") == 2 or mc.getAttr(surf + ".formV") == 2): mc.warning("surface is periodic. fk controls skipped") ################ ADD mensaje de atributo ################ mc.addAttr(main_ctrl, ln="joints", at="message") mc.addAttr(main_ctrl, ln="follicles", at="message") mc.addAttr(main_ctrl, ln="surface", at="message") if mc.attributeQuery("i_am_the_surface", node=surf, exists=True) == False: mc.addAttr(surf, ln="i_am_the_surface", at="message") mc.connectAttr(main_ctrl + ".surface", surf + ".i_am_the_surface") for j, f in izip(bind_jnts, fols): mc.addAttr(j, ln="i_am_a_joint", at="message") mc.addAttr(f, ln="i_am_a_follicle", at="message") mc.connectAttr(main_ctrl + ".joints", j + ".i_am_a_joint") mc.connectAttr(main_ctrl + ".follicles", f + ".i_am_a_follicle")
def rebuild(self): ''' Rebuild the wire deformer from the recorded deformerData ''' # Rebuild deformer wire = super(WireData, self).rebuild() # Check Wire Curves for curve in self.influenceData.iterkeys(): if not mc.objExists(curve): pts = self.influenceData[curve]['cvList'] knots = self.influenceData[curve]['knots'] degree = self.influenceData[curve]['degree'] mc.curve(p=pts, k=knots, d=degree, n=curve) # Check Base Curves for curve in self.influenceBaseData.iterkeys(): if not mc.objExists(curve): pts = self.influenceBaseData[curve]['cvList'] knots = self.influenceBaseData[curve]['knots'] degree = self.influenceBaseData[curve]['degree'] curve = mc.curve(p=pts, k=knots, d=degree, n=curve) mc.setAttr(curve + '.v', 0) # Check Dropoff Locators for locator in self.dropoffLocatorData.iterkeys(): if mc.objExists(self.dropoffLocatorData[locator]['parent']): mc.delete(self.dropoffLocatorData[locator]['parent']) # Set Deformer Attributes mc.setAttr(wire + '.crossingEffect', self.crossingEffect) mc.setAttr(wire + '.tension', self.tension) mc.setAttr(wire + '.localInfluence', self.localInfluence) mc.setAttr(wire + '.rotation', self.rotation) # Connect wire curves for curve in self.influenceData.iterkeys(): mc.connectAttr(curve + '.worldSpace[0]', wire + '.deformedWire[' + str(self.influenceData[curve]['index']) + ']', f=True) # Connect base curves for curve in self.influenceBaseData.iterkeys(): mc.connectAttr(curve + '.worldSpace[0]', wire + '.baseWire[' + str(self.influenceBaseData[curve]['index']) + ']', f=True) # Set Influence Attributes for influence in self.influenceData.iterkeys(): infIndex = self.influenceData[influence]['index'] mc.setAttr(wire + '.dropoffDistance[' + str(infIndex) + ']', self.influenceData[influence]['dropoff']) mc.setAttr(wire + '.scale[' + str(infIndex) + ']', self.influenceData[influence]['scale']) # Recreate Dropoff Locators for locator in self.dropoffLocatorData.iterkeys(): locIndex = self.dropoffLocatorData[locator]['index'] param = self.dropoffLocatorData[locator]['parameter'] parent = self.dropoffLocatorData[locator]['parent'] env = self.dropoffLocatorData[locator]['envelope'] percent = self.dropoffLocatorData[locator]['percent'] mc.select(parent + '.u[' + str(param) + ']') newLoc = mc.dropoffLocator(env, percent, wire) mc.setAttr(wire + '.wireLocatorTwist[' + str(locIndex) + ']', self.dropoffLocatorData[locator]['twist']) if parent != newLoc: newLoc = mc.rename(newLoc, parent) locShape = mc.listRelatives(newLoc, s=True, ni=True)[0] if locator != locShape: locator = mc.rename(locShape, locator) # Return result return wire
def rebuild(self): ''' Rebuild the wire deformer from the recorded deformerData ''' # Rebuild deformer wire = super(WireData, self).rebuild() # Check Wire Curves for curve in self.influenceData.iterkeys(): if not mc.objExists(curve): pts = self.influenceData[curve]['cvList'] knots = self.influenceData[curve]['knots'] degree = self.influenceData[curve]['degree'] mc.curve(p=pts,k=knots,d=degree,n=curve) # Check Base Curves for curve in self.influenceBaseData.iterkeys(): if not mc.objExists(curve): pts = self.influenceBaseData[curve]['cvList'] knots = self.influenceBaseData[curve]['knots'] degree = self.influenceBaseData[curve]['degree'] curve = mc.curve(p=pts,k=knots,d=degree,n=curve) mc.setAttr(curve+'.v',0) # Check Dropoff Locators for locator in self.dropoffLocatorData.iterkeys(): if mc.objExists(self.dropoffLocatorData[locator]['parent']): mc.delete(self.dropoffLocatorData[locator]['parent']) # Set Deformer Attributes mc.setAttr(wire+'.crossingEffect',self.crossingEffect) mc.setAttr(wire+'.tension',self.tension) mc.setAttr(wire+'.localInfluence',self.localInfluence) mc.setAttr(wire+'.rotation',self.rotation) # Connect wire curves for curve in self.influenceData.iterkeys(): mc.connectAttr(curve+'.worldSpace[0]',wire+'.deformedWire['+str(self.influenceData[curve]['index'])+']',f=True) # Connect base curves for curve in self.influenceBaseData.iterkeys(): mc.connectAttr(curve+'.worldSpace[0]',wire+'.baseWire['+str(self.influenceBaseData[curve]['index'])+']',f=True) # Set Influence Attributes for influence in self.influenceData.iterkeys(): infIndex = self.influenceData[influence]['index'] mc.setAttr(wire+'.dropoffDistance['+str(infIndex)+']',self.influenceData[influence]['dropoff']) mc.setAttr(wire+'.scale['+str(infIndex)+']',self.influenceData[influence]['scale']) # Recreate Dropoff Locators for locator in self.dropoffLocatorData.iterkeys(): locIndex = self.dropoffLocatorData[locator]['index'] param = self.dropoffLocatorData[locator]['parameter'] parent = self.dropoffLocatorData[locator]['parent'] env = self.dropoffLocatorData[locator]['envelope'] percent = self.dropoffLocatorData[locator]['percent'] mc.select(parent+'.u['+str(param)+']') newLoc = mc.dropoffLocator(env,percent,wire) mc.setAttr(wire+'.wireLocatorTwist['+str(locIndex)+']',self.dropoffLocatorData[locator]['twist']) if parent != newLoc: newLoc = mc.rename(newLoc,parent) locShape = mc.listRelatives(newLoc,s=True,ni=True)[0] if locator != locShape: locator = mc.rename(locShape,locator) # Return result return wire
def ribbonize(surf_tr, equal=1, num_of_ctrls=5, num_of_jnts=29, prefix="", constrain=1, add_fk=0, wire=0): attrs = [ ".tx", ".ty", ".tz", ".rx", ".ry", ".rz", ".sx", ".sy", ".sz", ".v" ] if prefix == "": mc.warning("care to name it?") return else: prefix = prefix + "_" ##################################################### surf_tr = mc.rename(surf_tr, prefix + "ribbon_surface") surf = mc.listRelatives(surf_tr, shapes=True)[0] # freeze transformations and delete the surface history mc.makeIdentity(surf_tr, t=True, r=True, s=True, apply=True) mc.delete(surf_tr, ch=True) # duplicate surface curves to determine the direction u_curve = mc.duplicateCurve(surf_tr + ".v[.5]", local=True, ch=0) v_curve = mc.duplicateCurve(surf_tr + ".u[.5]", local=True, ch=0) # delete the history just in case mc.delete(surf_tr, ch=True) u_length = mc.arclen(u_curve) v_length = mc.arclen(v_curve) if u_length < v_length: mc.reverseSurface(surf_tr, d=3, ch=False, rpo=True) mc.reverseSurface(surf_tr, d=0, ch=False, rpo=True) parameter = ".parameterU" other_param = ".parameterV" # correct u_curve after reversing to calculate the length u_curve_corr = mc.duplicateCurve(surf_tr + ".v[.5]", local=True, ch=0)[0] ############################################################################# # selected surface is periodic or open? (cylinder or a plane) if mc.getAttr(surf + ".formU") == 2 or mc.getAttr(surf + ".formV") == 2: curve_type = "periodic" divider_for_ctrls = num_of_ctrls elif mc.getAttr(surf + ".formU") == 0 or mc.getAttr(surf + ".formV") == 0: curve_type = "open" divider_for_ctrls = num_of_ctrls - 1 ############################################################################# param_ctrls = param_from_length(u_curve_corr, num_of_ctrls, curve_type, "uv") param_joints = param_from_length(u_curve_corr, num_of_jnts, curve_type, "uv") length = mc.arclen(u_curve_corr) mc.delete(u_curve, v_curve, u_curve_corr) ############################################################################ # create groups, main control and main control offset final_group = mc.group(n=prefix + "ribbon_grp", em=True) ctrl_joints_grp = mc.group(n=prefix + "ctrl_joints_grp", em=True) ctrl_grp = mc.group(n=prefix + "ctrls_grp", em=True) follicles_grp = mc.group(n=prefix + "follicles_grp", em=True) rig_grp = mc.group(n=prefix + "rig_grp", em=True) main_ctrl = mc.circle(n=prefix + "ctrl_main", nr=(0, 1, 0), r=length / 5, ch=0)[0] main_ctrl_offset = mc.group(n=prefix + "ctrl_main_offset", em=True) mc.parent(main_ctrl, main_ctrl_offset) mc.parent(ctrl_grp, main_ctrl) mc.parent(main_ctrl_offset, rig_grp, final_group) mc.parent(surf_tr, ctrl_joints_grp, follicles_grp, rig_grp) # move main_ctrl_offset to the center of the surfaces bbox (in case its pivot is somewhere else) mid_point = get_bbox_center(surf_tr) for attr, mid_pnt_el in izip(attrs[:3], mid_point): mc.setAttr(main_ctrl_offset + attr, mid_pnt_el) ############################################################################ fols = [] fols_tr = [] bind_jnts = [] bnd_joints_rad = (length / 60) / (float(num_of_jnts) / 40) for x in range(num_of_jnts): fol = mc.createNode("follicle") mc.setAttr(fol + ".visibility", 0) temp_fol = mc.listRelatives(fol, p=True)[0] fols_tr.append( mc.rename(temp_fol, "{}follicle_{:02d}".format(prefix, x + 1))) fols.append(mc.listRelatives(fols_tr[-1], s=True)[0]) # connect follicle shapes to their transforms mc.connectAttr(fols[-1] + ".outTranslate", fols_tr[-1] + ".translate", f=True) mc.connectAttr(fols[-1] + ".outRotate", fols_tr[-1] + ".rotate", f=True) # attach follicle shapes to the surface mc.connectAttr(surf + ".worldMatrix[0]", fols[-1] + ".inputWorldMatrix") mc.connectAttr(surf + ".local", fols[-1] + ".inputSurface") mc.setAttr(fols[-1] + parameter, param_joints[x]) mc.setAttr(fols[-1] + other_param, 0.5) mc.parent(fols_tr[-1], follicles_grp) # create final bind joints on the surface bind_jnts.append( mc.createNode("joint", n="{}bnd_jnt_{:02d}".format(prefix, x + 1))) mc.parent(bind_jnts[-1], fols_tr[-1], r=True) mc.setAttr(bind_jnts[-1] + ".radius", bnd_joints_rad) set_color(bind_jnts, "mid_blue") #create temp follicles for control offset groups to align temp_fols = [] temp_fols_tr = [] for x in range(num_of_ctrls): temp_fols.append(mc.createNode("follicle")) temp_fols_tr.append(mc.listRelatives(temp_fols[-1], p=True)[0]) mc.connectAttr(temp_fols[-1] + ".outTranslate", temp_fols_tr[-1] + ".translate", f=True) mc.connectAttr(temp_fols[-1] + ".outRotate", temp_fols_tr[-1] + ".rotate", f=True) mc.connectAttr(surf + ".worldMatrix[0]", temp_fols[-1] + ".inputWorldMatrix") mc.connectAttr(surf + ".local", temp_fols[-1] + ".inputSurface") #################################################### if equal == 1: for x, temp_fol in enumerate(temp_fols): mc.setAttr(temp_fol + parameter, param_ctrls[x]) mc.setAttr(temp_fol + other_param, 0.5) if equal == 0: v = 0 for temp_fol in temp_fols: mc.setAttr(temp_fol + parameter, v) mc.setAttr(temp_fol + other_param, 0.5) v = v + (1.0 / divider_for_ctrls) #################################################### #create controls and control joints controls = ctrl_maker(prefix, ctrl_type="cube", count=num_of_ctrls, deg=3, sp=8) ctrl_ofs_grps = [] ctrl_joints = [] ctrl_jnt_ofs_grps = [] ctrl_joints_rad = bnd_joints_rad * 2 ik_ctrl_scale = (length / 35) / (float(num_of_ctrls) / 5) for x, ctrl in enumerate(controls): ctrl_ofs_grp = mc.group(ctrl, n="{}_offset".format(ctrl)) mc.delete(mc.parentConstraint(temp_fols_tr[x], ctrl_ofs_grp)) ctrl_ofs_grps.append(ctrl_ofs_grp) #scale ik controls ctrl_shapes = mc.listRelatives(ctrl, s=True) for ctrl_shape in ctrl_shapes: ctrl_cvs_count = mc.getAttr(ctrl_shape + ".controlPoints", size=True) mc.scale(ik_ctrl_scale, ik_ctrl_scale, ik_ctrl_scale, "{}.cv[0:{}]".format(ctrl_shape, ctrl_cvs_count - 1), r=True, ocp=True) #create the control joints ctrl_joints.append( mc.createNode("joint", n="{}ctrl_jnt_{:02d}".format(prefix, x + 1))) #set the radius of controls joints to 2 times that of the surface joints mc.setAttr(ctrl_joints[x] + ".radius", ctrl_joints_rad) #create offset groups for ctrl joints ctrl_jnt_ofs_grp = mc.group(ctrl_joints[-1], n="{}_offset".format(ctrl_joints[-1])) mc.delete(mc.parentConstraint(temp_fols_tr[x], ctrl_jnt_ofs_grp)) ctrl_jnt_ofs_grps.append(ctrl_jnt_ofs_grp) ### set_color(controls, "green") set_color(ctrl_joints, "red") mc.parent(ctrl_ofs_grps, ctrl_grp) mc.parent(ctrl_jnt_ofs_grps, ctrl_joints_grp) lock_hide(ctrl_ofs_grps, attrs[:9]) lock_hide(ctrl_jnt_ofs_grps, attrs[:9]) mc.delete(temp_fols_tr) #################################################### #determine if constraint or connection method is chosen if constrain == 0: for (c, j) in izip(controls, ctrl_joints): for attr in attrs[:7]: #skip scale attributes mc.connectAttr(c + attr, j + attr) mc.parentConstraint(main_ctrl, ctrl_joints_grp, mo=True) mc.scaleConstraint(main_ctrl, ctrl_joints_grp) #scale the follicles with the main control for flt in fols_tr: mc.connectAttr(main_ctrl + ".sx", flt + ".sx") mc.connectAttr(main_ctrl + ".sx", flt + ".sy") mc.connectAttr(main_ctrl + ".sx", flt + ".sz") elif constrain == 1: for (c, j) in izip(controls, ctrl_joints): mc.parentConstraint(c, j) mc.scaleConstraint(c, j) #scale the follicles with the main control for flt in fols_tr: mc.scaleConstraint(main_ctrl, flt) ####################################################################### if wire == True and num_of_ctrls > 1: temp_crv = mc.duplicateCurve(surf_tr + ".v[.5]", n=prefix + "wire_crv", local=False, ch=0)[0] if num_of_ctrls == 2: degree = 1 else: degree = 3 wire_crv = mc.curve(p=param_from_length( temp_crv, num_of_ctrls + (num_of_ctrls - 1), "open", "world"), d=degree) mc.delete(temp_crv) wire_crv = mc.rename( wire_crv, prefix + "wire_crv" ) # if name at the creation time, the shape doesn't get renamed mc.delete(wire_crv, ch=True) wire = mc.wire(surf_tr, gw=False, en=1.0, ce=0.0, li=0.0, dds=(0, 50), w=wire_crv, n=prefix + "wire")[0] mc.connectAttr(main_ctrl + ".sx", wire + ".scale[0]") cps = param_from_length(wire_crv, num_of_ctrls, "open", "uv", normalized=False) for cp in cps: mc.select("{}.u[{}]".format(wire_crv, cp), r=True) mc.dropoffLocator(1.0, 1.0, wire) mc.select(cl=True) for x, ctrl in enumerate(controls): mc.connectAttr(ctrl + ".rx", "{}.wireLocatorTwist[{}]".format(wire, x)) wire_grp = mc.group(wire_crv, wire_crv + "BaseWire", n=prefix + "wire_crv_grp") mc.parent(wire_grp, rig_grp) lock_hide([wire_grp], attrs[:9]) wire_skin_cluster = mc.skinCluster(ctrl_joints, wire_crv, dr=2, mi=2, bm=0)[0] else: #bind the surface to the joints nurbs_skin_cluster = mc.skinCluster(ctrl_joints, surf_tr, dr=2, mi=num_of_ctrls - 1, ns=num_of_ctrls * 5, bm=0, n=prefix + "skinCluster")[0] mc.skinPercent(nurbs_skin_cluster, surf_tr, pruneWeights=0.2) if wire == True and num_of_ctrls == 1: mc.warning("wire skipped. at least 2 controls needed") ########################################################################################## mc.setAttr(surf_tr + ".v", 0) mc.setAttr(rig_grp + ".v", 0) mc.connectAttr(main_ctrl + ".sx", main_ctrl + ".sy") mc.connectAttr(main_ctrl + ".sx", main_ctrl + ".sz") mc.aliasAttr("Scale", main_ctrl + ".sx") set_color(main_ctrl, "yellow") mc.connectAttr(main_ctrl_offset + ".sx", main_ctrl_offset + ".sy") mc.connectAttr(main_ctrl_offset + ".sx", main_ctrl_offset + ".sz") mc.aliasAttr("Scale", main_ctrl_offset + ".sx") #lock and hide attributes lock_hide([ final_group, follicles_grp, ctrl_joints_grp, surf_tr, ctrl_grp, rig_grp ], attrs[:9]) lock_hide([ctrl_grp, main_ctrl, main_ctrl_offset], attrs[7:]) lock_hide(controls, attrs[7:]) #clear selection mc.select( cl=True ) #if selection isn't cleared a control joint gets added to the bind joints set #create a set with bind joints bind_jnts_set = mc.sets(n=prefix + "bind_jnts_set") mc.sets(bind_jnts, add=bind_jnts_set) mc.select(cl=True) ik_ctrls_set = mc.sets(n=prefix + "ik_ctrls_set") mc.sets(controls, add=ik_ctrls_set) mc.select(cl=True) controls_set = mc.sets(n=prefix + "controls_set") mc.sets(main_ctrl, ik_ctrls_set, add=controls_set) ########################################################################################## if add_fk == 1 and mc.getAttr(surf + ".formU") != 2 and mc.getAttr( surf + ".formV") != 2: fk_ctrls, fk_ctrl_off_grps = make_fk_ctrls(prefix, num_of_ctrls) mc.parent(fk_ctrl_off_grps[0], ctrl_grp) #scale fk controls fk_ctrl_scale = ik_ctrl_scale * 2 for fk_ctrl in fk_ctrls: fk_ctrl_shapes = mc.listRelatives(fk_ctrl, s=True) for fk_ctrl_shape in fk_ctrl_shapes: fk_ctrl_cvs_count = mc.getAttr(fk_ctrl_shape + ".controlPoints", size=True) mc.scale(fk_ctrl_scale, fk_ctrl_scale, fk_ctrl_scale, "{}.cv[0:{}]".format(fk_ctrl_shape, fk_ctrl_cvs_count - 1), r=True, ocp=True) #add fk controls to a set mc.select(cl=True) fk_ctrls_set = mc.sets(n=prefix + "fk_ctrls_set") mc.sets(fk_ctrls, add=fk_ctrls_set) ######## ik_ctrl_constr_grps = [ mc.group(ctrl, n=ctrl + "_constr_grp") for ctrl in controls ] [ mc.xform(ik_ctrl_constr_grp, piv=(0, 0, 0), os=True) for ik_ctrl_constr_grp in ik_ctrl_constr_grps ] for ik, fk in izip(controls[:-1], fk_ctrl_off_grps): mc.delete(mc.parentConstraint(ik, fk)) for fk, ik in izip(fk_ctrls, ik_ctrl_constr_grps[:-1]): mc.parentConstraint(fk, ik) #constrain last ik ctrl mc.parentConstraint(fk_ctrls[-1], ik_ctrl_constr_grps[-1], mo=True) lock_hide(ik_ctrl_constr_grps, attrs[:9]) ######## set_color(fk_ctrls, "blue") lock_hide(fk_ctrl_off_grps, attrs[:9]) mc.sets(fk_ctrls_set, add=controls_set) mc.select(cl=True) elif add_fk == 1 and (mc.getAttr(surf + ".formU") == 2 or mc.getAttr(surf + ".formV") == 2): mc.warning("surface is periodic. fk controls skipped") ################ADD MESSAGE ATTRS################ mc.addAttr(main_ctrl, ln="joints", at="message") mc.addAttr(main_ctrl, ln="follicles", at="message") mc.addAttr(main_ctrl, ln="surface", at="message") if mc.attributeQuery("i_am_the_surface", node=surf, exists=True) == False: mc.addAttr(surf, ln="i_am_the_surface", at="message") mc.connectAttr(main_ctrl + ".surface", surf + ".i_am_the_surface") for j, f in izip(bind_jnts, fols): mc.addAttr(j, ln="i_am_a_joint", at="message") mc.addAttr(f, ln="i_am_a_follicle", at="message") mc.connectAttr(main_ctrl + ".joints", j + ".i_am_a_joint") mc.connectAttr(main_ctrl + ".follicles", f + ".i_am_a_follicle")