Parent Constraint In-depth

[vimeo url=”http://vimeo.com/82095352″]

In this video I explain the anatomy of parent constraint and how you can create your own custom constraint using Maya utility nodes. I also wrote some python code to add a parent-target manually which resolves an issue with the way Maya adds parent constraint targets by default.

The pace of this video is intermediate by nature. If you are a beginner to maya code, nodes & matrices you can still follow the video. Observe, Do and Repeat. You won’t find it difficult.

We are including the python code below for you to work with.

[divider top=”no”]
import math
import maya.cmds as cmds
import maya.OpenMaya as om

def _addParentConstTarget(driver, driven, parentConst, wtsIndex):
    # calculate offset - this same as creating parent constraint with maintain offset
    trans = _getTransformOffset(driver, driven, 'translate', cmds.getAttr('%s.rotateOrder'%driven))
    rotation = _getTransformOffset(driver, driven, 'rotate', cmds.getAttr('%s.rotateOrder'%driven))
    # connect required target index inputs
    cmds.addAttr(parentConst, ln='%sW%s'%(driver,wtsIndex), sn='w%s'%wtsIndex, at='double', min=0, max=1, dv=1, k=1)
    cmds.connectAttr('%s.parentMatrix[0]'%driver, '%s.target[%s].targetParentMatrix'%(parentConst, wtsIndex))
    cmds.connectAttr('%s.scale'%driver, '%s.target[%s].targetScale'%(parentConst, wtsIndex))
    cmds.connectAttr('%s.rotateOrder'%driver, '%s.target[%s].targetRotateOrder'%(parentConst, wtsIndex))
    cmds.connectAttr('%s.rotate'%driver, '%s.target[%s].targetRotate'%(parentConst, wtsIndex))
    cmds.connectAttr('%s.rotatePivotTranslate'%driver, '%s.target[%s].targetRotateTranslate'%(parentConst, wtsIndex))
    cmds.connectAttr('%s.rotatePivot'%driver, '%s.target[%s].targetRotatePivot'%(parentConst, wtsIndex))
    cmds.connectAttr('%s.translate'%driver, '%s.target[%s].targetTranslate'%(parentConst, wtsIndex))
    cmds.connectAttr('%s.%sW%s'%(parentConst,driver,wtsIndex), '%s.target[%s].targetWeight'%(parentConst, wtsIndex))
    #setting offset value
    cmds.setAttr('%s.target[%s].targetOffsetTranslateX'%(parentConst, wtsIndex), trans[0])
    cmds.setAttr('%s.target[%s].targetOffsetTranslateY'%(parentConst, wtsIndex), trans[1])
    cmds.setAttr('%s.target[%s].targetOffsetTranslateZ'%(parentConst, wtsIndex), trans[2])
    cmds.setAttr('%s.target[%s].targetOffsetRotateX'%(parentConst, wtsIndex), rotation[0])
    cmds.setAttr('%s.target[%s].targetOffsetRotateY'%(parentConst, wtsIndex), rotation[1])
    cmds.setAttr('%s.target[%s].targetOffsetRotateZ'%(parentConst, wtsIndex), rotation[2])

def _getTransformOffset(startObj, endObj, type, rotateOrder):
    mStart = om.MMatrix()
    mEnd = om.MMatrix()
    start = cmds.getAttr('%s.wm[0]'%startObj)
    end = cmds.getAttr('%s.wm[0]'%endObj)
    om.MScriptUtil().createMatrixFromList(start,mStart)
    om.MScriptUtil().createMatrixFromList(end,mEnd)
    mOutputMatrix = om.MTransformationMatrix(mEnd * mStart.inverse())
    if type == 'translate':
        vTrans = om.MVector(mOutputMatrix.getTranslation(om.MSpace.kTransform))
        return vTrans.x,vTrans.y,vTrans.z
    if type == 'rotate':
        vRotation = om.MEulerRotation(mOutputMatrix.eulerRotation().reorder(rotateOrder))
        return math.degrees(vRotation.x), math.degrees(vRotation.y), math.degrees(vRotation.z)