def rigCluster(handle, uvs, rotOrder, n, names): """Control creation method for surface clusters""" ctrl, ctrlGrp = makeWeightedCtrl(uvs, n, rotOrder, names) handle.setParent(ctrlGrp.getParent()) # (initial) ctrlGrp.mat * ctrl.m * parGrp.m * (initial) ctrlGrp.invMat # is how we get ctrl rots into surface (and presumably handle) space cgm = mu.rotMat(ctrlGrp.matrix) handleXform = mu.xformFromSpaces( [cgm.inverse(), ctrl.m, ctrl.getParent().m, cgm], n.format(type="xforms"), rotOrder) handleXform.outputTranslate >> handle.t handleXform.outputRotate >> handle.r handleXform.outputScale >> handle.s # invert double translations for ctrl and parGrp for xfm in (ctrl.getParent(), ctrl): xn = xfm.name() grp = pmc.group(xfm, p=xfm.getParent(), n=xn + "_DBL_XFM_GRP") invTrans = pmc.nt.MultiplyDivide(n=xn + "_INV_XFM") xfm.t >> invTrans.input1 invTrans.input2.set(-1, -1, -1) invTrans.output >> grp.t return ctrl
def makeBulgeCtrl(handle, ctrCtrl, n, names, rotOrder): """Make inner control for softmod. Diamond for the softMod handle itself""" ctrlGrpRotMat = mu.rotMat(ctrCtrl.controlGroup.get().matrix) hCtrl = jc.makeCtrlShape(n.format(type=names["control"]), rotOrder, shape="diamond") for sh in hCtrl.getShapes(): ctrCtrl.create.inputs()[0].radius >> sh.create.inputs()[0].radius pmc.scale(sh.cv, .8, .8, .8) hCtrl.setParent(ctrCtrl) pmc.makeIdentity(hCtrl) # handle xforms must be ctrl in ctrCtrlGrp AND ctrCtrl space but without # any of their actual xforms parGrp = ctrCtrl.getParent() handleXform = mu.xformFromSpaces([ ctrlGrpRotMat.inverse(), ctrCtrl.inverseMatrix, parGrp.inverseMatrix, hCtrl.m, parGrp.matrix, ctrCtrl.matrix, ctrlGrpRotMat ], n.format(type="xforms"), rotOrder) handleXform.outputTranslate >> handle.t handleXform.outputRotate >> handle.r handleXform.outputScale >> handle.s return hCtrl
def makeJntDynamic(surf, jnt, ctrl, rotOrder, n): """Given surface, joint and ctrl hierarchy, make the ctrl affect the joint via a new "follicle" and (dynamic offset) orient constraint.""" # allow UV limiting to be turned off via jnt attr # which blends between unclamped and clamped: U >> R, V >> G limitSwitch = pmc.nt.BlendColors(n=n.format(type="limitSwitch")) jnt.SurfaceUV_LimitsOnJoint >> limitSwitch.blender # if limit is OFF use un-clamped U (cpos.u >> color2) jnt.clampedU >> limitSwitch.color1R jnt.clampedV >> limitSwitch.color1G jnt.preclampedU >> limitSwitch.color2R jnt.preclampedV >> limitSwitch.color2G # make follicle, connect (optionally) limited params to it dynPosi = pmc.nt.PointOnSurfaceInfo(n=n.format(type="dynposi")) surf.local >> dynPosi.inputSurface limitSwitch.outputR >> dynPosi.u limitSwitch.outputG >> dynPosi.v # all axes dynMat = su.makeFakeFollMatrix(dynPosi, n.format(type="dynMat"), "xyz", rotOrder) # create fakeFoll matrix nodes for all three axes at static params, # for autoRot and ctrl rotations ctrlGrp = ctrl.controlGroup.get() statPosi = ctrlGrp.translate.inputs()[0] statTripMat = su.makeFakeFollMatrix(statPosi, n.format(type="statTripMat"), "xyz", rotOrder) jnt.jointOrient.set(0, 0, 0) # wtAdd switches between autorotate along surf movements autoSwitch = pmc.nt.WtAddMatrix(n=n.format(type="autoSwitch")) dynMat.output >> autoSwitch.wtMatrix[0].matrixIn ctrl.autoRotate >> autoSwitch.wtMatrix[0].weightIn statTripMat.output >> autoSwitch.wtMatrix[1].matrixIn flip = pmc.nt.Reverse(n=n.format(type="autoRotFlip")) ctrl.autoRotate >> flip.inputX flip.outputX >> autoSwitch.wtMatrix[1].weightIn # getting all xforms caused variably by normals/tangents # and ctrl rotations into ONE matrix decompose it # autoSwitch[0] * cg.inv[1] * c.m[2] * parConG.m[3] * cg.m[4] parGrp = ctrl.getParent() jntRot = mu.xformFromSpaces( [autoSwitch.matrixSum, ctrlGrp.im, ctrl.m, parGrp.m, ctrlGrp.m], n.format(type="xforms"), rotOrder) dynPosi.position >> jnt.translate jntRot.outputRotate >> jnt.rotate
def parentCtrlTo(ctrl, parCtrl, n, rotOrder): """Forge the connections between a parent control and the ctrl it will be affecting.""" # affect the parent's sticky location before parent relationship setParentStickyGrp(ctrl, parCtrl, n, rotOrder) parGrp = parCtrl.controlGroup.get() ctrlGrp = ctrl.controlGroup.get() # parent controls can have parents affecting them too! parPar = parCtrl.getParent() # parCtrl xforms UNDONE by its own grp (as always), # but re-spaced into target ctrl grp matList = [ctrlGrp.m, parGrp.im, parCtrl.m, parPar.m, parGrp.m, ctrlGrp.im] constGrp = ctrl.getParent() if ctrl.listConnections(type="cluster"): if parGrp.r.isConnected(): pmc.warning( "While possible, parenting both joint and cluster controllers " "together can have odd results. Recommended use is joints only." ) parGrp.r.disconnect() # have to tiptoe around deformer controls to avoid creating a cycle constGrp = constGrp.getParent() # solidify the space transforming "bookend" matrices # ie not actual controlling ones for i, m in enumerate(matList): if m not in (parCtrl.m, parPar.m): matList[i] = m.get() constXform = mu.xformFromSpaces(matList, n.format(type="xforms"), rotOrder) connectParentXforms(parCtrl, constGrp, constXform, n) connectParentVis(parCtrl, constGrp, n) parCtrl.childControls.connect(ctrl.parentControls, nextAvailable=True) print("Control {0} successfully parented to {1}.".format( ctrl.name(), parCtrl.name()))