def setupSpineIkNode(ctlList, jntList, surf=None, crv=None, nodeName='beings_splineik', namer=None): """ Create an ik spline system using controls in the ctlList that will drive jnts in jntList """ if not namer: namer = utils.Namer('char', 'cn', 'spine') if not surf: surf = surfaceFromNodes(ctlList) surf = getShape(surf) if not crv: crv = curveFromNodes(ctlList) crv = getShape(crv) ikNode = MC.createNode('transform', name=namer(nodeName)) MC.parent(MC.listRelatives(surf, parent=1)[0], ikNode) MC.parent(MC.listRelatives(crv, parent=1)[0], ikNode) namer.setTokens(r='ik') names = ['stretch_%s' % ascii_lowercase[i] for i in range(len(jntList))] stretchJnts = utils.dupJntList(jntList, names, namer) #rebuild the curve so that we get more even parameterization for 'even stretch' #joints. Use a 7 degree curve so we can build with a single span evenStretchCrv = MC.rebuildCurve(MC.listRelatives(crv, parent=1)[0], ch=1, rpo=0, rt=0, end=1, kr=2, kcp=0, kep=1, kt=0, s=1, d=7, tol=0.01)[0] evenStretchCrv = MC.rename(evenStretchCrv, "%s_evenstretch" % crv) MC.parent(evenStretchCrv, ikNode) evenStretchCrv = getShape(evenStretchCrv) nodes = {'posi':[], 'cps': [], 'posiUp':[], 'xform':[], 'xformUp':[]} #for each joint, get the param at the rebuilt curve. Use this position to get #the closest point on the surface, then get the u and v values at that surface #point. for i, jnt in enumerate(stretchJnts): suff = ascii_lowercase[i] #get point on rebuild curve near each jnt poci = MC.createNode('pointOnCurveInfo', n='%s_%s_evenstretch_poci' % (ikNode, suff)) MC.connectAttr("%s.worldSpace[0]" % evenStretchCrv, '%s.ic' % poci) MC.setAttr('%s.pr' % poci, closestParamOnCurve(jnt, evenStretchCrv)) #get closest point on surface cps = MC.createNode("closestPointOnSurface", n='%s_%s_evenstretch_cps' % (ikNode, suff)) MC.connectAttr("%s.worldSpace[0]" % surf, '%s.is' % cps) MC.connectAttr("%s.p" % poci, "%s.ip" % cps) nodes['cps'].append(cps) MC.addAttr(ikNode, ln='evenStretchAmt', min=0, max=1, k=1) for i, jnt in enumerate(stretchJnts): #create a point on surface info node at each point suff = ascii_lowercase[i] posi = MC.createNode('pointOnSurfaceInfo', n='%s_%s_posi' % (ikNode, suff)) posiUp = MC.createNode('pointOnSurfaceInfo', n='%s_%s_up_posi' % (ikNode, suff)) MC.connectAttr('%s.worldSpace[0]' % surf, '%s.is' % posi) MC.connectAttr('%s.worldSpace[0]' % surf, '%s.is' % posiUp) u, v = closestParamOnSurface(jnt, surf) for node in [posi, posiUp]: blender = MC.createNode("blendColors", name='%s_%s_evenstretch_blc' % (ikNode, suff)) MC.connectAttr('%s.evenStretchAmt' % ikNode, '%s.blender' % blender) #as the evenStretchAmt increases, shift towards the u value of the even stretch crv MC.connectAttr("%s.u" % nodes['cps'][i], "%s.c1r" % blender) MC.setAttr("%s.c2r" % blender, u) MC.connectAttr("%s.opr" % blender, '%s.u' % node) MC.setAttr('%s.v' % posi, v) MC.setAttr('%s.v' % posiUp, v-.25) posXform = MC.createNode("transform", n='%s_%s_grp' % (ikNode, suff)) upXform = MC.createNode("transform", n='%s_%s_up_grp' % (ikNode, suff)) MC.parent(posXform, ikNode) MC.parent(upXform, ikNode) MC.connectAttr("%s.p" % posi, "%s.t" % posXform) MC.connectAttr("%s.p" % posiUp, "%s.t" % upXform) MC.pointConstraint(posXform, jnt) utils.fixJointConstraints(posXform) nodes['posi'].append(posi) nodes['posiUp'].append(posiUp) nodes['xform'].append(posXform) nodes['xformUp'].append(upXform) #now that all the xforms are created, aim them at each other and #measure the start stretch distance MC.addAttr(ikNode, ln='inputScaleAmt', dv=1, k=1) for i in range(len(stretchJnts)-1): suff = ascii_lowercase[i] nextSuff = ascii_lowercase[i+1] dst = MC.createNode('distanceBetween', n='%s_%s_to_%s_dist' % \ (ikNode,suff, nextSuff)) MC.connectAttr("%s.p" % nodes['posi'][i], '%s.p1' % dst) MC.connectAttr("%s.p" % nodes['posi'][i+1], '%s.p2' % dst) MC.addAttr(ikNode, ln = "origDistToNext_%s" % suff, h=False, dv=MC.getAttr("%s.d" % dst)) stretchMdn = MC.createNode("multiplyDivide", n='%s_%s_stretch_mdn' % (ikNode, suff)) MC.connectAttr('%s.d' % dst, '%s.input1X' % stretchMdn) MC.connectAttr('%s.origDistToNext_%s' % (ikNode, suff), '%s.input2X' % stretchMdn) MC.setAttr('%s.operation' % stretchMdn, 2) stretchSclMdn = MC.createNode("multiplyDivide", n='%s_%s_stretch_scl_mdn' % (ikNode, suff)) MC.setAttr('%s.operation' % stretchSclMdn, 2) MC.connectAttr('%s.outputX' % stretchMdn, '%s.input1X' % stretchSclMdn) MC.connectAttr('%s.inputScaleAmt' % ikNode, '%s.input2X' % stretchSclMdn) MC.addAttr(ikNode, ln = "stretchAmt_%s" % suff, k=1) MC.connectAttr('%s.outputX' % stretchSclMdn, '%s.stretchAmt_%s' \ % (ikNode, suff)) #connect stretch amount to joint scale MC.connectAttr('%s.stretchAmt_%s' % (ikNode, suff), '%s.sy' % stretchJnts[i]) #aim the xforms MC.aimConstraint(nodes['xform'][i+1], nodes['xform'][i], aimVector=[0,1,0], upVector=[1,0,0], worldUpType='object', worldUpObject=nodes['xformUp'][i]) MC.orientConstraint(nodes['xform'][i], stretchJnts[i]) utils.fixJointConstraints(stretchJnts[i]) utils.fixJointConstraints(nodes['xform'][i]) MC.orientConstraint(ctlList[-1], stretchJnts[-1]) utils.fixJointConstraints(stretchJnts[-1]) nsJnts, nsPosJnts, esUps = setupIkSplineJnts(jntList, crv, surf, ikNode, namer = namer, nodeName='%s_ns' % nodeName, tipCtl = ctlList[-1]) MC.addAttr(ikNode, ln='stretchAmt', min=0, max=1, dv=0, k=1) utils.blendJointChains(nsJnts, stretchJnts, jntList, '%s.stretchAmt' % ikNode, namer) MC.setAttr("%s.v" % nsJnts[0], 0) MC.setAttr("%s.v" % stretchJnts[0], 0) return ikNode
def _makeLayout(self, namer): jntCnt = self.options.getValue('numBones') + 1 MC.select(cl=1) jnts = [] layoutCtlZeros = [] rigCtls = [] ups = [] for i in range(jntCnt): jnt = MC.joint(p=[0,i*2, 0], n=namer(r='bnd', alphaSuf=i)) self.registerBindJoint(jnt) jnts.append(jnt) if i < jntCnt -1: rigCtl = control.makeControl(namer(r='fk', alphaSuf=i), color='green', shape='cube') control.setEditable(rigCtl, True) self.registerControl(rigCtl, 'rig') rigCtls.append(rigCtl) layoutCtl = control.makeControl(namer('layout_ctl', r='fk', alphaSuf=i), color='purple', shape='sphere') if i < (jntCnt-1): upCtl = control.makeControl(namer('layout_twist_ctl', r='fk', alphaSuf=i), color='blue', shape='triangle', t=[1.5,0,0], s=[.2, .2, .2]) up = MC.createNode('transform', n=namer('layout_twist_up', r='fk', alphaSuf=i)) MC.parent(up, upCtl) MC.setAttr('%s.t' % up, 2, 0, 0, type='double3') ups.append(up) utils.snap(jnt, upCtl) MC.parent(upCtl, layoutCtl) self.registerControl(upCtl, 'layout', uk=['ry']) utils.snap(jnt, layoutCtl) utils.snap(jnt, rigCtl) layoutCtlZeros.append(utils.insertNodeAbove(layoutCtl)) MC.parent(rigCtl, jnt) MC.pointConstraint(layoutCtl, jnt) utils.fixJointConstraints(jnt) self.registerControl(layoutCtl, 'layout', uk=['t']) MC.select(jnt) MC.select(cl=1) #aim each fkControl at the next one for i in range(len(layoutCtlZeros)-1): nextCtl = MC.listRelatives(layoutCtlZeros[i+1])[0] thisZero = layoutCtlZeros[i] thisCtl = MC.listRelatives(thisZero)[0] control.centeredCtl(jnts[i], jnts[i+1], rigCtls[i]) upVec = [1,0,0] MC.aimConstraint(nextCtl, thisCtl, aimVector=[0,1,0], upVector=[1,0,0], worldUpVector=[1,0,0]) MC.aimConstraint(nextCtl, jnts[i], aimVector=[0,1,0], upVector=upVec, worldUpType='object', worldUpObject = ups[i]) utils.fixJointConstraints(thisCtl) lck = ['tx', 'ty', 'tz', 'rx', 'rz', 'sx', 'sy', 'sz'] for attr in lck: par = MC.listRelatives(ups[i], parent=1)[0] #MC.setAttr('%s.%s' % (ups[i], attr) , l=1) MC.setAttr('%s.%s' % (par, attr) , l=1)
def setupIkSplineJnts(jntList, crv, surf, ikNode, nodeName='beings_splineik', namer=None, tipCtl=None): """ Setup a splineIk system, but use a nurbs surface to control orientation. This allows full twist control along the length of the chain @param jntList: the list of original joints; they will be duplicated @param crv: the curve to use for the spline ik system @param surf: the surface to use for the twist @param namer: the namer to use for naming; a generic will be assigned if none provided @param tipCtl: a control to use for orienting the last joint. If none provided, it will be oriented to the plane """ if not namer: namer = utils.Namer('char', 'cn', 'spine') namer.setTokens(r='ik') #use the splineik node to get joints to 'slip' alone the curve. These are intermediate #joints, we're just using their position to get us a point on the nurbs surface so we #can use the surface for orientation jntNames = ['%s_pos_jnt_%s' % (nodeName, ascii_lowercase[i]) for i in range(len(jntList))] splinePosJnts = utils.dupJntList(jntList, jntNames, namer) for jnt in splinePosJnts: control.setLockTag(jnt, uu=['t', 'r']) #these are the actual joints that will be oriented and positioned correctly jntNames = ['%s_jnt_%s' % (nodeName,ascii_lowercase[i]) for i in range(len(jntList))] splineJnts = utils.dupJntList(jntList, jntNames, namer) handle, ee = MC.ikHandle(solver='ikSplineSolver', sj=splinePosJnts[0], ee=splinePosJnts[-1], curve=crv, simplifyCurve=False, parentCurve=False, createCurve=False) MC.parent(handle, ikNode) xforms = [] ups = [] for i, jnt in enumerate(splinePosJnts): dcm = MC.createNode('decomposeMatrix', n=namer('%s_splinejnt_dcm' % nodeName, alphaSuf=i)) cps = MC.createNode('closestPointOnSurface', n=namer('%s_splinejnt_cps' % nodeName, alphaSuf=i)) posi = MC.createNode('pointOnSurfaceInfo', n=namer('%s_splinejnt_posi' % nodeName, alphaSuf=i)) xform = MC.createNode('transform', n=namer('%s_splinejnt_grp' % nodeName, alphaSuf=i)) xformUp = MC.createNode('transform', n=namer('%s_splinejnt_up_grp' % nodeName, alphaSuf=i)) MC.parent(xform, ikNode) MC.parent(xformUp, ikNode) MC.connectAttr('%s.worldMatrix' % jnt, '%s.inputMatrix' % dcm) MC.connectAttr("%s.worldSpace[0]" % surf, '%s.inputSurface' % cps) MC.connectAttr("%s.outputTranslate" % dcm, "%s.ip" % cps) MC.connectAttr("%s.p" % cps, "%s.t" % xform) MC.connectAttr("%s.worldSpace[0]" % surf, '%s.inputSurface' % posi) MC.connectAttr("%s.u" % cps, "%s.u" % posi) MC.setAttr("%s.v" % cps, MC.getAttr("%s.v" % cps) + .1) MC.connectAttr("%s.p" % posi, "%s.t" % xformUp) xforms.append(xform) ups.append(xformUp) MC.pointConstraint(splinePosJnts[i], splineJnts[i]) for i in range(len(splinePosJnts)-1): MC.aimConstraint(splinePosJnts[i+1], xforms[i], aimVector=[0,1,0], upVector=[1,0,0], worldUpType='object', worldUpObject=ups[i]) utils.fixJointConstraints(xforms[i]) MC.orientConstraint(xforms[i], splineJnts[i]) utils.fixJointConstraints(splineJnts[i]) if tipCtl: MC.orientConstraint(tipCtl, splineJnts[-1]) utils.fixJointConstraints(splineJnts[-1]) MC.setAttr("%s.v" % splinePosJnts[0], 0) MC.setAttr("%s.v" % handle, 0) return (splineJnts, splinePosJnts, ups)