選択したボーンにダイナミクスを一発で入れるメモ

選択したボーンにダイナミクスを一発で入れるメモ

正確にはPython

セカンダリモーションの補助に使えるかもしれない

http://barakmoshe.blogspot.jp/2013/09/tutorial-how-to-set-up-automatic.html





/////////////////////////////////////////////////////////////////////////////////
'''
Our final script needs to handle all of the steps that we went over in an automated and intelligent
way. We want to make sure that this script is scalable so that we can use it on multiple joint
hierarchies. We will also want to do some case handling to make sure that the script that we make
will communicate any type of error to the user to help them properly debug any issues that may occur.
'''

import maya.cmds as cmds


class AutoOverlap:
    '''
    This class contains functionality that can support creating a real-time automatic overlap rig.
    '''
    def __init__(self):
        '''
        Constructor
        '''
 
    def createCurveFromJoints(self, jointChain):
        '''
        Takes in an array of joints and generates a curve that aligns with the input joints.
        '''
        jointPositions = []
     
        # For each joint selected, query its world space position as a tuple and append to a list.
        for joints in jointChain:
            # We want to avoid adding CV's to our curve that won't line up with a joint.
            if cmds.objectType( joints, isType='joint' ):
                pos = cmds.xform(joints, q=True, ws=True, t=True)
                jointPositions.append(tuple(pos))
            else:
                raise RuntimeError("Method 'createCurveFromJoints()' expects a joint chain.")
         
        # Creates a curve with a cv located along each joint from generated list.
        newCurve = cmds.curve(ep=jointPositions)
     
        newCurve = cmds.rename(newCurve, 'driverCurve_' + jointChain[0])
     
        return newCurve
 
    # Due to the fact the make curve dynamic mel command does not give you anything to track,
    # we will want to make the dynamic curve manually. This will allow us to create
    # an instance of any object created so that we can maintain a data driven and scalable system.
    def makeCurveDynamic(self, curve):
        '''
        Takes in curve and makes it dynamic. Returns list of all nodes created in the process.
        '''
        # Get the curve shape from the transform selection.
        curveShape = cmds.listRelatives(curve, shapes=True)[0]
     
        if cmds.objectType( curveShape, isType='nurbsCurve' ):
            # Create nodes needed for simulation
            outputCurve = cmds.createNode( 'nurbsCurve', n=('outputCurve_' + curve) )
            hairSystem = cmds.createNode( 'hairSystem', n=('hairSystemShape_' + curve) )
            nucleus = cmds.createNode( 'nucleus', n=('nucleus_' + curve) )
            follicle = cmds.createNode( 'follicle', n=('follicleShape_' + curve) )
            cmds.setAttr((follicle + '.restPose'), 1)
         
            # Connect nodes to set up simulation
         
            # Rebuild curve
            rebuildCurve1 = cmds.createNode( 'rebuildCurve', n='rebuildCurve1')
            rebuiltCurveOutput = cmds.createNode( 'nurbsCurve', n=( curve + 'rebuiltCurveShape1') )
         
            # Generate curve output
            cmds.connectAttr((curveShape + '.worldSpace[0]'), (rebuildCurve1 + '.inputCurve'))
            cmds.connectAttr((rebuildCurve1 + '.outputCurve'), (rebuiltCurveOutput + '.create'))
         
            # Connect curves to follicle
            cmds.connectAttr((curve + '.worldMatrix[0]'), (follicle + '.startPositionMatrix'))
            cmds.connectAttr((rebuiltCurveOutput + '.local'), (follicle + '.startPosition'))
         
            # Connect follicle to output curve
            cmds.connectAttr((follicle + '.outCurve'), (outputCurve + '.create'))
         
            # Connect time to hair system and nucleus
            cmds.connectAttr('time1.outTime', (nucleus + '.currentTime'))
            cmds.connectAttr('time1.outTime', (hairSystem + '.currentTime'))
         
            # Connect hair system and nucleus together
            cmds.connectAttr((hairSystem + '.currentState'), (nucleus + '.inputActive[0]'))
            cmds.connectAttr((hairSystem + '.startState'), (nucleus + '.inputActiveStart[0]'))
            cmds.connectAttr((nucleus + '.outputObjects[0]'), (hairSystem + '.nextState'))
            cmds.connectAttr((nucleus + '.startFrame'), (hairSystem + '.startFrame'))
         
            # Connect hair system to follicle
            cmds.connectAttr((hairSystem + '.outputHair[0]'), (follicle + '.currentPosition'))
            cmds.connectAttr((follicle + '.outHair'), (hairSystem + '.inputHair[0]'))
         
            # Return all created objects from simulation.
            return [outputCurve, hairSystem, nucleus, follicle, rebuildCurve1, rebuiltCurveOutput]
         
        else:
            raise RuntimeError("Method 'makeCurveDynamic()' expects a curve.")
     
    def createControlCurve(self, jointChain):
        '''
        Creates control curve with necessary attributes for auto overlap rig.
        Returns control curve
        '''
        if cmds.objectType( jointChain[0], isType='joint' ):
            baseCtrlName = 'baseCtrl_' + jointChain[0]
         
            # Create control curve
            baseControl = cmds.circle( n=baseCtrlName, nr=(1, 0, 0) )
         
            # Set attributes on control curve
            cmds.addAttr(ln='DynamicFollicle', sn='DynamicFollicle', at='float', h=False)
            cmds.addAttr(ln='AutoOverlap', sn='AutoOverlap', at='bool', k=True, h=False)
            cmds.addAttr(ln='StopFollicle', sn='StopFollicle', at='float', k=True, h=False)
         
            cmds.setAttr( baseCtrlName + '.StopFollicle', 1, l=True)      
            cmds.setAttr( baseCtrlName + '.DynamicFollicle', k=False, cb=True)
         
            # Snap control curve to base joint and clean up control curve
            baseJointConstraint = cmds.parentConstraint(jointChain[0], baseControl, mo=False)
            cmds.delete(baseJointConstraint)
            cmds.makeIdentity( baseControl, apply=True, t=1, r=1, s=1, n=2 )
         
            return baseControl[0]
         
        else:
            raise RuntimeError("Method 'createControlCurve()' expects a joint as the first index.")
     
    def createAutoOverlapExpression(self, baseCtrl, hairSystem, nucleus):
        '''
        Takes in control curve and nucleus and connects them with expression.
        '''
     
        # Break time connections from hair system and nucleus
        nucCurrTime = '%s.currentTime' % nucleus
        hairCurrTime = '%s.currentTime' % hairSystem
        cmds.disconnectAttr('time1.outTime', hairCurrTime)
        cmds.disconnectAttr('time1.outTime', nucCurrTime)
     
        aoExpression = ('if (' + baseCtrl + '.AutoOverlap == 1) { \n'
                        '\t' + nucleus + '.currentTime += 1; \n'
                        '\tfloat $refresh_tx = ' + baseCtrl + '.translateX; \n'
                        '\tfloat $refresh_ty = ' + baseCtrl + '.translateY; \n'
                        '\tfloat $refresh_tz = ' + baseCtrl + '.translateZ; \n'
                        '\tfloat $refresh_rx = ' + baseCtrl + '.rotateX; \n'
                        '\tfloat $refresh_ry = ' + baseCtrl + '.rotateY; \n'
                        '\tfloat $refresh_rz = ' + baseCtrl + '.rotateZ; \n\n'
                        '} else if (' + baseCtrl + '.AutoOverlap == 0) { \n'
                        '\t' + nucleus + '.currentTime = ' + baseCtrl + '.StopFollicle; \n}'
                        )
        # Set up auto overlap expression
        cmds.expression(n = 'AutoOverlap', string = aoExpression)
     
        # Connect current time of nucleus to current time of hair system
        cmds.connectAttr(nucCurrTime, hairCurrTime)

# We're going to move our core functionality into a helper function.
def createAutoOverlapChain(jointHierarchy):
    '''
    Take in joint hierarchy and applied an automatic follow through rig to it.
    '''
 
    # Create auto overlap chain from joint hierarchy. If one joint or no joints are selected, stop the script and prompt the user.
    if jointHierarchy and cmds.objectType( jointHierarchy[0], isType='joint' ) and len(joints) > 1:
        ao = AutoOverlap()
     
        # We can now call our createCurve method to generate our curve.
        generatedCurve = ao.createCurveFromJoints(jointHierarchy)
     
        # Make our generated curve dynamic.
        dynamicCurveObjects = ao.makeCurveDynamic(generatedCurve)
     
        # Create spline IK handle from a base joint, an end joint, and a curve.
        splineIK = cmds.ikHandle(sj=joints[0], ee=joints[-1], sol='ikSplineSolver', c=dynamicCurveObjects[0], ccv=False, p=2, w=.5)
     
        # Create control curve.
        controlCurve = ao.createControlCurve(jointHierarchy)
     
        # Parent constrain control curve to follicle curve.
        cmds.parentConstraint(controlCurve, generatedCurve, mo=True)
     
        # Create auto overlap expression.
        ao.createAutoOverlapExpression(controlCurve, dynamicCurveObjects[1], dynamicCurveObjects[2])

        # Group all objects created by makeCurvesDynamic command.
        dynamicGrp = cmds.group(dynamicCurveObjects, n='dynamicCurve_' + controlCurve + '_grp' )
        cmds.parent(generatedCurve, dynamicGrp)
        cmds.parent(splineIK[0], dynamicGrp)
     
        # Hide any unused nodes from view port.
        unusedObjects = cmds.listRelatives( dynamicGrp, allDescendents=True )
        for objects in unusedObjects:
            cmds.setAttr((objects + '.visibility'), 0)
 
        # Return group containing all needed objects to make curve dynamic.
        return dynamicGrp
    else:
        cmds.confirmDialog( title='Please select joint.', message='Please make sure to select a joint with at least one child joint.' )
        raise RuntimeError("Selection was not a joint with at least one child joint.")

#####################################################################################################
##                                 We're going to begin our script here.                           ##
## Let's leave this part of the script out of the class. We can input a joint chain in other ways. ##
#####################################################################################################

#  Select the joint hierarchy from the base joint.
joints = cmds.ls(dag=1, ap=1, sl=1, type="joint")

# If the joint name is layered with '|', stop the script and alert the user.
for j in joints[0]:
    if j == '|':
        cmds.confirmDialog( title='Please rename joint.', message=('Joint "' + joints[0] + '" has | characters dividing the name. Please rename the joint.') )
        raise RuntimeError("Joint cannot have dividers in name.")


#  Create automatic overlap rig.
createAutoOverlapChain(joints)

/////////////////////////////////////////////////////////////////////////////////