# IK Back Script

Here is a script I finished up a couple of weeks ago for scripting an IK back. All that’s left is the neck, head, and arms… Then the hard part is figuring out how to correctly connect them all!

```import maya.cmds as cmds
import bm_curveCube as curveCube
import bm_jointGeo as bm_jointGeo

# In all scripts, joints and controls must have a rot order of either ** YZX or ZXY.
# That means that all objects will point down the ** X axis and their secondary axis Y or Z and that orientation set to X
# ** Problem: spline curves only support joints that are oriented down the X axis.

# joint -e  -oj yxz -secondaryAxisOrient xup -ch -zso;
# cmds.joint
#cmds.joint(cmds.ls(sl=1,o=1),edit=1,orientJoint="yxz",secondaryAxisOrient="xup",children=1,zeroScaleOrient=1,rotationOrder="zxy")
# And use ORIENT groups!
class ikBack(object):
def __init__(self):
self.name = "ikBack"
self.divisions = 6

def setupBack(self):
cmds.select(cl=1)
self.lowerBackLoc = cmds.xform("lowerBack",q=1,t=1,ws=1)
self.upperBackLoc = cmds.xform("upperBack",q=1,t=1,ws=1)
self.backLen = self.upperBackLoc[1] - self.lowerBackLoc[1]
self.jointLen = self.backLen / self.divisions

a = 1
while(a < self.divisions):
cmds.joint(n=self.name + "_" + str((a+1)) + "_B",p=(self.lowerBackLoc[0],self.lowerBackLoc[1] + self.jointLen * a,self.lowerBackLoc[2]),rad=.3)
a += 1

cmds.joint(self.lowerBackJnt,edit=1,orientJoint="xzy",secondaryAxisOrient="yup",children=1,zeroScaleOrient=1,rotationOrder="yzx")

# setup ik setup
self.ikSpline = cmds.ikHandle(sj=self.lowerBackJnt,ee=self.upperBackJnt,sol="ikSplineSolver",scv=0,n="back_IK_#")
# [u'ikSpline2', u'effector1', u'curve1']
self.ikSpline[2] = cmds.rename(self.ikSpline[2],"back_CRV_#")
cmds.hilite(self.ikSpline[2])
cmds.select(self.ikSpline[2] + ".cv[4:8]")
self.upperBackCluster = cmds.cluster(n="upperBack_Cluster_#")
cmds.setAttr(self.upperBackCluster[1] + ".rotateOrder",2)

cmds.hilite(self.ikSpline[2])
cmds.select(self.ikSpline[2] + ".cv[0:3]")
self.lowerBackCluster = cmds.cluster(n="lowerBack_Cluster_#")
cmds.setAttr(self.lowerBackCluster[1] + ".rotateOrder",2)

self.upperBackCtrl = curveCube.curveCube()
cmds.xform(self.upperBackCtrl.myCube,t=(self.upperBackLoc))
cmds.FreezeTransformations(self.upperBackCtrl)
cmds.setAttr(self.upperBackCtrl.myCube + ".rotateOrder",2)
cmds.delete(self.upperBackCtrl.myCube,ch=1)
self.upperBackCtrl.myCube = cmds.rename(self.upperBackCtrl.myCube,"upperBack_ANIM")
cmds.parentConstraint(self.upperBackCtrl.myCube,self.upperBackCluster[1],mo=0)

self.lowerBackCtrl = curveCube.curveCube()
cmds.xform(self.lowerBackCtrl.myCube,t=(self.lowerBackLoc))
cmds.FreezeTransformations(self.lowerBackCtrl)
cmds.setAttr(self.lowerBackCtrl.myCube + ".rotateOrder",2)
cmds.delete(self.lowerBackCtrl.myCube,ch=1)
self.lowerBackCtrl.myCube = cmds.rename(self.lowerBackCtrl.myCube,"lowerBack_ANIM")
cmds.parentConstraint(self.lowerBackCtrl.myCube,self.lowerBackCluster[1],mo=1)
cmds.select(cl=1)
bm_jointGeo.jntGeo()

# setup advanced twist so that the shoulders and hips both control the twist
cmds.setAttr(self.ikSpline[0] + ".dTwistControlEnable",1)
cmds.setAttr(self.ikSpline[0] + ".dWorldUpType",4)
cmds.setAttr(self.ikSpline[0] + ".dWorldUpAxis",4)
cmds.setAttr(self.ikSpline[0] + ".dWorldUpVectorY",0)
cmds.setAttr(self.ikSpline[0] + ".dWorldUpVectorZ",-1)
cmds.setAttr(self.ikSpline[0] + ".dWorldUpVectorEndY",0)
cmds.setAttr(self.ikSpline[0] + ".dWorldUpVectorEndZ",-1)
cmds.connectAttr(self.lowerBackCtrl.myCube + ".matrix",self.ikSpline[0] + ".dWorldUpMatrix")
cmds.connectAttr(self.upperBackCtrl.myCube + ".matrix",self.ikSpline[0] + ".dWorldUpMatrixEnd")

# setup squash stretch
self.distanceDim = cmds.arclen(self.ikSpline[2],ch=1)
self.spineLen = cmds.getAttr(self.distanceDim + ".arcLength")

# distance factor makes the ditance value 1. If it stretches or squashes, that becomes the scale
# value of the joint
self.distanceFactor = cmds.createNode("multiplyDivide")
cmds.setAttr(self.distanceFactor + ".op",2)
cmds.setAttr(self.distanceFactor + ".i2x",self.spineLen)
cmds.connectAttr(self.distanceDim + ".arcLength",self.distanceFactor + ".i1x")

myJnts.reverse()
myJnts.insert(0,self.lowerBackJnt)

i = 1
while i < self.divisions - 1:
cmds.connectAttr(self.distanceFactor + ".ox",myJnts[i] + ".sx")
i += 1

self.inverseNode = cmds.createNode("multiplyDivide")
cmds.setAttr(self.inverseNode + ".op",2)
cmds.setAttr(self.inverseNode + ".i1x",1)
cmds.connectAttr(self.distanceFactor + ".ox",self.inverseNode + ".i2x")
# these next "Exponent Nodes" will setup the squash and stretch for our joints
self.expNode1 = cmds.createNode("multiplyDivide")
cmds.setAttr(self.expNode1 + ".op",3)
cmds.setAttr(self.expNode1 + ".i2x",1.6)
cmds.connectAttr(self.inverseNode + ".ox",self.expNode1 + ".i1x")

self.expNode2 = cmds.createNode("multiplyDivide")
cmds.setAttr(self.expNode2 + ".op",3)
cmds.setAttr(self.expNode2 + ".i2x",1.2)
cmds.connectAttr(self.inverseNode + ".ox",self.expNode2 + ".i1x")

self.expNode3 = cmds.createNode("multiplyDivide")
cmds.setAttr(self.expNode3 + ".op",3)
cmds.setAttr(self.expNode3 + ".i2x",.5)
cmds.connectAttr(self.inverseNode + ".ox",self.expNode3 + ".i1x")

cmds.connectAttr(self.expNode3 + ".ox",myJnts[1] + ".sy")
cmds.connectAttr(self.expNode3 + ".ox",myJnts[1] + ".sz")
cmds.connectAttr(self.expNode3 + ".ox",myJnts[4] + ".sy")
cmds.connectAttr(self.expNode3 + ".ox",myJnts[4] + ".sz")
cmds.connectAttr(self.expNode2 + ".ox",myJnts[2] + ".sy")
cmds.connectAttr(self.expNode2 + ".ox",myJnts[2] + ".sz")
cmds.connectAttr(self.expNode2 + ".ox",myJnts[3] + ".sy")
cmds.connectAttr(self.expNode2 + ".ox",myJnts[3] + ".sz")

# create the FK joints and controls

self.backJnts.reverse()
self.backFKjnt = cmds.joint(n="back_FK",p=self.lowerBackLoc)
self.lowerBackFKjnt = cmds.joint(n="lowerBack_FK",p=cmds.xform(self.backJnts[1],q=1,t=1,ws=1))
self.upperBackFKjnt = cmds.joint(n="upperBack_FK",p=cmds.xform(self.backJnts[3],q=1,t=1,ws=1))
self.neckFKjnt = cmds.joint(n="neck_FK",p=cmds.xform(self.backJnts[5],q=1,t=1,ws=1))
cmds.joint(self.backFKjnt,edit=1,orientJoint="xzy",secondaryAxisOrient="yup",children=1,zeroScaleOrient=1,rotationOrder="yzx")

self.lowerBack_FK_ANIM = cmds.circle()
self.lowerBack_FK_ANIM[0] = cmds.rename(self.lowerBack_FK_ANIM[0],"body_ANIM")
cmds.xform(self.lowerBack_FK_ANIM[0],ro=(90,0,0),t=self.lowerBackLoc,ws=1)
cmds.connectAttr(self.lowerBack_FK_ANIM[0] + ".ry",self.ikSpline[0] + ".roll")
cmds.setAttr(self.lowerBack_FK_ANIM[0] + ".rotateOrder",3)
cmds.FreezeTransformations(self.lowerBack_FK_ANIM[0])

cmds.parent(self.backFKjnt,self.lowerBack_FK_ANIM[0])
self.lowerBackCtrlGRP = cmds.group(self.lowerBackCtrl.myCube,n="lowerBackCtrl_GRP")
self.upperBackCtrlGRP = cmds.group(self.upperBackCtrl.myCube,n="upperBackCtrl_GRP")

cmds.parent(self.lowerBackCtrlGRP,self.backFKjnt)
cmds.parent(self.upperBackCtrlGRP,self.neckFKjnt)

self.lowerBackANIM = cmds.circle()
self.lowerBackANIM[0] = cmds.rename(self.lowerBackANIM[0],"lowerBack_FK_ANIM")
self.lowerBackANIM_ORIENT = cmds.group(self.lowerBackANIM[0],n=self.lowerBackANIM[0] + "_ORIENT")
cmds.xform(self.lowerBackANIM_ORIENT,t=cmds.xform(self.lowerBackFKjnt,q=1,t=1,ws=1),ro=(90,0,0))
cmds.setAttr(self.lowerBackANIM[0] + ".rotateOrder",2)

self.upperBackANIM = cmds.circle()
self.upperBackANIM[0] = cmds.rename(self.upperBackANIM[0],"upperBack_FK_ANIM")
self.upperBackANIM_ORIENT = cmds.group(self.upperBackANIM[0],n=self.upperBackANIM[0] + "_ORIENT")
cmds.xform(self.upperBackANIM_ORIENT,t=cmds.xform(self.upperBackFKjnt,q=1,t=1,ws=1),ro=(90,0,0))
cmds.setAttr(self.upperBackANIM[0] + ".rotateOrder",2)

cmds.parent(self.lowerBackANIM_ORIENT,self.backFKjnt)
cmds.parent(self.lowerBackFKjnt,self.lowerBackANIM[0])
cmds.parent(self.upperBackANIM_ORIENT,self.lowerBackFKjnt)
cmds.parent(self.upperBackFKjnt,self.upperBackANIM[0])

self.ikGRP = cmds.group(self.ikSpline[0],self.ikSpline[2],self.upperBackCluster,self.lowerBackCluster,n="ikBack_IK_GRP")
self.ctrlGRP = cmds.group(self.lowerBack_FK_ANIM,self.lowerBackJnt,n="ikBack_CTRL_GRP")
cmds.group(self.ikGRP,self.ctrlGRP,n="ikBack_ALL")

myBack = ikBack()
myBack.setupBack()
```