예제 #1
0
 def setOptionVars(self, optionVarDict):
     '''Only set the optionVars that are non-default. Remove optionVar if value=defaultValue.
     '''
     # update dict from optionVars
     for k,v in optionVarDict.iteritems():
         optVarKey = self.optionVarPrefix+k
         logger.info(maya.stringTable[ 'y_CommandWithOptionVars.kSettingOptVar'  ] %(optVarKey,v))
         if self.optionVarDefaults[k] == v:
             maya.cmds.optionVar(remove=optVarKey)  # remove if it exists
         else:
             if isinstance(v, (float)):
                 maya.cmds.optionVar(fv=(optVarKey,v))
             elif isinstance(v, (int)):
                 maya.cmds.optionVar(iv=(optVarKey,v))
             elif isinstance( v, (str,unicode) ):
                 maya.cmds.optionVar(sv=(optVarKey,v))
             elif isinstance(v, (list)) and len(v) > 0 and isinstance(v[0], (float)):
                 maya.cmds.optionVar(fv=(optVarKey,v[0]))  # explicitly add first value
                 for f in v[1:]:                           # then append the rest
                     maya.cmds.optionVar(fva=(optVarKey,f))
             elif isinstance(v, (list)) and len(v) > 0 and isinstance(v[0], (int)):
                 maya.cmds.optionVar(iv=(optVarKey,v[0]))  # explicitly add first value
                 for f in v[1:]:                           # then append the rest
                     maya.cmds.optionVar(iva=(optVarKey,f))
             elif isinstance(v, (list)) and len(v) > 0 and isinstance(v[0], (str,unicode)):
                 maya.cmds.optionVar(sv=(optVarKey,v[0]))  # explicitly add first value
                 for f in v[1:]:                           # then append the rest
                     maya.cmds.optionVar(sva=(optVarKey,f))
             else:
                 raise Exception('Unknown type %s for %s'%(type(v), v))
예제 #2
0
	def executeCommandCB(self, miscBool=None):
		'''Callback to be used by a menuItem.
		Performs command with the specified optionVar preferences.
		'''
		logger.info(maya.stringTable[ 'y_RigidBody.kGetOptVarValues'  ])
		optionVarDict = self.getOptionVars()

		# REVISIT: May want to pass in parameters to the command a different way
		logger.info(maya.stringTable[ 'y_RigidBody.kExecuteCmd'  ])
		optionVarDictWithDefaults = self.optionVarDefaults.copy()
		optionVarDictWithDefaults.update(optionVarDict)

		# called directly from menu item
		if miscBool:
			# if there's only 1 object in select then use its name + 'Set'
			# otherwise let command determine name
			name = None
			list = maya.cmds.ls(sl=True,type='transform')
			if list and len(list)==1:
				name = list[0] + 'Set'
				baseName = name
				numInstances = 1
				while maya.cmds.objExists(name):
					name = '{0}{1}'.format(baseName,numInstances)
					numInstances += 1
			else:
				# otherwise use the name stored in the options
				name = optionVarDictWithDefaults['name']

			optionVarDictWithDefaults['name'] = self.uniqueName(name)

		returnVal = self.command(**optionVarDictWithDefaults)

		return returnVal
예제 #3
0
 def resetOptionBoxToDefaultsCB(self, miscBool=None):
     '''Callback for the "Reset" Option Dialog menuitem.
     Resets the optionVars in the dialog to the Prefs default.
     Note: Requires OptionBox Dialog to be created.
     '''        
     logger.info(maya.stringTable['y_CommandWithOptionVars.kResetDefaults' ]%miscBool)
     self.setOptionVars(self.optionVarDefaults)
     self.setWidgetValues(self.optionVarDefaults)
예제 #4
0
    def saveOptionBoxPreferencesCB(self, miscBool=None):
        '''Callback for the "Save" Option Dialog menuitem.
        Saves the optionVars from the dialog
        Note: Requires OptionBox Dialog to be created.
        '''        
        logger.info(maya.stringTable['y_CommandWithOptionVars.kRetrieveWidgetValue'])
        optionVarDict = self.getWidgetValues()

        logger.info(maya.stringTable['y_CommandWithOptionVars.kSavingOptVars' ])
        self.setOptionVars(optionVarDict)
예제 #5
0
 def hideOptionBoxCB(self, miscBool=None):
     '''Callback for "Close" Option Dialog button
     Saves the optionVars from the dialog, and hides dialog.
     Note: Requires OptionBox Dialog to be created.
     '''
     logger.info(maya.stringTable['y_CommandWithOptionVars.kCloseOBox' ])
     if (self.optionBox != ''):
         maya.cmds.control(self.optionBox, edit=True, visibleChangeCommand='')
     self.saveOptionBoxPreferencesCB()
     self.optionBoxClosing()
     maya.mel.eval('hideOptionBox()')
예제 #6
0
 def executeCommandAndHideOptionBoxCB(self, miscBool=None):
     '''Callback for "Apply and Close" Option Dialog button
     Saves the optionVars from the dialog, executes the command, and hides dialog.
     Note: Requires OptionBox Dialog to be created.
     '''
     logger.info(maya.stringTable['y_CommandWithOptionVars.kExecCmdAndCloseOBox' ])
     returnVal = self.executeCommandAndSaveCB()
     
     if (self.optionBox != ''):
         maya.cmds.control(self.optionBox, edit=True, visibleChangeCommand='')
     self.optionBoxClosing()
     maya.mel.eval('hideOptionBox()')
     return returnVal
예제 #7
0
    def executeCommandCB(self, miscBool=None):
        '''Callback to be used by a menuItem.
        Performs command with the specified optionVar preferences.
        '''
        logger.info(maya.stringTable[ 'y_CommandWithOptionVars.kGetOptVarValues'  ])
        optionVarDict = self.getOptionVars()

        # REVISIT: May want to pass in parameters to the command a different way
        logger.info(maya.stringTable[ 'y_CommandWithOptionVars.kExecuteCmd'  ])
        optionVarDictWithDefaults = self.optionVarDefaults.copy()
        optionVarDictWithDefaults.update(optionVarDict)
        returnVal = self.command(**optionVarDictWithDefaults)
        
        return returnVal
예제 #8
0
 def getOptionVars(self):
     '''Create a dict by retrieving the optionVars, use the default value if
     optionVar not found.
     '''
     # start with defaults
     optionVarDict = self.optionVarDefaults.copy()
     
     # update dict from optionVars
     for k,v in optionVarDict.iteritems():
         # NOTE: optionVar has the prefix added.  The optionVarDict key does not
         optVarKey = self.optionVarPrefix+k
         if (maya.cmds.optionVar(exists=optVarKey)):
             optionVarDict[k] = maya.cmds.optionVar(q=optVarKey)
         logger.info(maya.stringTable[ 'y_CommandWithOptionVars.kGettingOptVar'  ]%(optVarKey,v))
             
     # return dict
     return optionVarDict        
예제 #9
0
    def createOptionDialog(self, optionVarOverrideDict=None, saveOptionVars=True):
        '''Callback for the MenuItem OptionBox.
        Create and show the Option Dialog for this command.
        Supplies the header and footer for the dialog.
        Calls `addOptionDialogWidgets` to create the widgets.
        '''
        # == Retrieve optionVars ==
        optionVarDict = self.getOptionVars()
        # override specified values with incoming dict if != None
        if optionVarOverrideDict != None:
            optionVarDict.update(optionVarOverrideDict)
            
        # == Dialog header ==
        layout = maya.mel.eval('getOptionBox()')
        maya.cmds.setParent(layout)
        maya.mel.eval('setOptionBoxCommandName("'+self.commandName+'")')
        maya.cmds.setUITemplate('DefaultTemplate', pushTemplate=True)
        maya.cmds.waitCursor(state=True)
        maya.cmds.tabLayout(tv=False, scr=True)

        parent = maya.cmds.columnLayout(adjustableColumn=True)
                
        # == Dialog attrs ==
        # Add parameters
        logger.info(maya.stringTable['y_CommandWithOptionVars.kAddWidgets'])
        self.optionVarToWidgetDict = self.addOptionDialogWidgets()
        # If nothing returned by the function addOptionDialogWidgets(),
        # then set it to an empty dict
        if self.optionVarToWidgetDict == None:
            logger.warning(maya.stringTable['y_CommandWithOptionVars.kReturnedNone'])
            self.optionVarToWidgetDict = {}
        # Create reverse dict (for optionMenuGrp widget)
        self.optionMenuGrp_enumToLabel = {}
        for k_labelToEnum, v_labelToEnum in self.optionMenuGrp_labelToEnum.iteritems():
            self.optionMenuGrp_enumToLabel[k_labelToEnum] = dict([(v,k) for k,v in v_labelToEnum.iteritems()])

        # Verify there is a defaultValue for each widgetKey
        missingDefaults = set(self.optionVarToWidgetDict.keys()) - set(self.optionVarDefaults.keys())
        if len(missingDefaults) > 0:
            raise ValueError('Missing default optionVar keys: %s'%str(missingDefaults))
        omittedWidgetKeys = set(self.optionVarDefaults.keys()) - set(self.optionVarToWidgetDict.keys())
        if len(omittedWidgetKeys) > 0:
            logger.warning(maya.stringTable['y_CommandWithOptionVars.kMissingWidgets']%str(missingDefaults))

        # Set Widget Values
        logger.info(maya.stringTable['y_CommandWithOptionVars.kSetWidgetValues'])
        # REVISIT: Put a try/catch around this??
        self.setWidgetValues(optionVarDict)
        
        # == Dialog footer ==
        maya.cmds.waitCursor(state=False)
        maya.cmds.setUITemplate(popTemplate=True)
        # * Buttons
        applyBtn = maya.mel.eval('getOptionBoxApplyBtn()')
        maya.cmds.button(applyBtn,
                         edit=True,
                         command=self.executeCommandAndSaveCB);        
        
        # * Titling and Help
        dlgTitle = self.l10nCommandName + maya.stringTable['y_CommandWithOptionVars.kOptionsTitle' ]
        maya.mel.eval('setOptionBoxTitle("'+dlgTitle+'")')

        if not self.commandHelpTag:
            self.commandHelpTag = '{0}Options'.format(self.commandName)

        maya.mel.eval('setOptionBoxHelpTag( "{0}" )'.format(self.commandHelpTag))

        # == Show OptionBox ==
        maya.mel.eval('showOptionBox()')

        # == Post show to set the menu items
        # Reference: performTextureToGeom
        # Handle Menu items
        gOptionBoxEditMenuSaveItem = maya.mel.eval('global string $gOptionBoxEditMenuSaveItem;   string $bullet_TMPSTR = $gOptionBoxEditMenuSaveItem;')
        gOptionBoxEditMenuResetItem = maya.mel.eval('global string $gOptionBoxEditMenuResetItem; string $bullet_TMPSTR = $gOptionBoxEditMenuResetItem;')        
        maya.cmds.menuItem(gOptionBoxEditMenuSaveItem,  edit=True, command=self.saveOptionBoxPreferencesCB)
        maya.cmds.menuItem(gOptionBoxEditMenuResetItem, edit=True, command=self.resetOptionBoxToDefaultsCB)
        maya.cmds.control(layout, edit=True, visibleChangeCommand=self.visibilityChangedCB)
        
        # Handle apply and close button here since showOptionBox() does not respect the set command
        applyAndCloseBtn = maya.mel.eval('getOptionBoxApplyAndCloseBtn()')
        closeBtn = maya.mel.eval('getOptionBoxCloseBtn()')
        maya.cmds.button(applyAndCloseBtn,
                         edit=True,
                         command=self.executeCommandAndHideOptionBoxCB)
        maya.cmds.button(closeBtn,
                         edit=True,
                         command=self.hideOptionBoxCB)
                         
        # Allow the subclass to make any modifications
        self.updateOptionBox()
예제 #10
0
    def command(
        rigidBodyA=None,
        rigidBodyB=None,
        parent=None,
        # Attrs
        constraintType=None,
        useReferenceFrame=None,
        linearDamping=None,
        linearSoftness=None,
        linearRestitution=None,
        angularDamping=None,
        angularSoftness=None,
        angularRestitution=None,
        linearConstraintX=None,
        linearConstraintY=None,
        linearConstraintZ=None,
        linearConstraintMin=None,
        linearConstraintMax=None,
        angularConstraintX=None,
        angularConstraintY=None,
        angularConstraintZ=None,
        angularConstraintMin=None,
        angularConstraintMax=None,
        linearLimitSoftness=None,
        linearLimitBias=None,
        linearLimitRelaxation=None,
        angularLimitSoftness=None,
        angularLimitBias=None,
        angularLimitRelaxation=None,
        linearMotorEnabled=None,
        linearMotorTargetSpeed=None,
        linearMotorMaxForce=None,
        angularMotorEnabled=None,
        angularMotorTargetSpeed=None,
        angularMotorMaxForce=None,
        linearSpringEnabledX=None,
        linearSpringEnabledY=None,
        linearSpringEnabledZ=None,
        linearSpringStiffness=None,
        linearSpringDamping=None,
        angularSpringEnabledX=None,
        angularSpringEnabledY=None,
        angularSpringEnabledZ=None,
        angularSpringStiffness=None,
        angularSpringDamping=None,
        breakable=None,
        breakingThreshold=None,
    ):
        logger.debug( maya.stringTable[ 'y_RigidBodyConstraint.kCreatingRBC'  ] \
                       % (rigidBodyA, rigidBodyB) )
        # List settable attrs (setAttr below)
        settableAttrs = [
            'constraintType',
            'useReferenceFrame',
            'linearDamping',
            'linearSoftness',
            'linearRestitution',
            'angularDamping',
            'angularSoftness',
            'angularRestitution',
            'linearConstraintX',
            'linearConstraintY',
            'linearConstraintZ',
            'linearConstraintMin',
            'linearConstraintMax',
            'angularConstraintX',
            'angularConstraintY',
            'angularConstraintZ',
            'angularConstraintMin',
            'angularConstraintMax',
            'linearLimitSoftness',
            'linearLimitBias',
            'linearLimitRelaxation',
            'angularLimitSoftness',
            'angularLimitBias',
            'angularLimitRelaxation',
            'linearMotorEnabled',
            'linearMotorTargetSpeed',
            'linearMotorMaxForce',
            'angularMotorEnabled',
            'angularMotorTargetSpeed',
            'angularMotorMaxForce',
            'linearSpringEnabledX',
            'linearSpringEnabledY',
            'linearSpringEnabledZ',
            'linearSpringStiffness',
            'linearSpringDamping',
            'angularSpringEnabledX',
            'angularSpringEnabledY',
            'angularSpringEnabledZ',
            'angularSpringStiffness',
            'angularSpringDamping',
            'breakable',
            'breakingThreshold',
        ]
        # Get the rigid body/bodies.
        rigids = [i for i in [rigidBodyA, rigidBodyB]
                  if i != None]  # list of non-None rigid bodies
        if len(rigids) == 0:  # if no rigids specified, then look at selection
            rigids = BulletUtils.getConnectedRigidBodies()
        logger.info(
            maya.stringTable['y_RigidBodyConstraint.kRigidBodiesToConnect'] %
            (rigids, parent))
        if len(rigids) == 0 or len(rigids) > 2:
            # TODO: this produces a pretty difficult to read error for the user.
            maya.OpenMaya.MGlobal.displayError(
                maya.
                stringTable['y_RigidBodyConstraint.kPleaseSelectRigidbodies'])
            return []
        if len(rigids) == 1 and locals()['constraintType'] in (
                eConstraintType.kRBConstraintHinge2,
                eConstraintType.kRBConstraintSixDOF2):
            maya.OpenMaya.MGlobal.displayError(maya.stringTable[
                'y_RigidBodyConstraint.kPleaseSelectTwoRigidbodies'])
            return []

        # Get Solver
        solver = BulletUtils.getSolver()
        # Create Node
        constraint = maya.cmds.createNode('bulletRigidBodyConstraintShape',
                                          parent=parent)
        # Set Attrs (optional, set if value != None)
        # Use the settableAttrs list above to qualify kwargs passed into the
        # function
        for k, v in locals().iteritems():
            if k in settableAttrs and v != None:
                if isinstance(v, list):
                    maya.cmds.setAttr('%s.%s' % (constraint, k),
                                      *v)  # covers float3 cases
                else:
                    maya.cmds.setAttr('%s.%s' % (constraint, k), v)
        # Connect
        maya.cmds.connectAttr((solver + ".outSolverInitialized"),
                              (constraint + ".solverInitialized"))
        maya.cmds.connectAttr((rigids[0] + ".outRigidBodyData"),
                              (constraint + ".rigidBodyA"))
        if len(rigids) > 1:
            maya.cmds.connectAttr((rigids[1] + ".outRigidBodyData"),
                                  (constraint + ".rigidBodyB"))
        maya.cmds.connectAttr((constraint + ".outConstraintData"),
                              (solver + ".rigidBodyConstraints"),
                              na=True)
        # REVISIT: Consider alternatives like a single initSystem bool attr
        #          instead of startTime and currentTime.
        #          Might be able to get around needing it at all
        maya.cmds.connectAttr((solver + ".startTime"),
                              (constraint + ".startTime"))
        maya.cmds.connectAttr((solver + ".currentTime"),
                              (constraint + ".currentTime"))

        # Translate (avg the rigid body positions)
        t = maya.cmds.xform(maya.cmds.listRelatives(rigids[0],
                                                    fullPath=True,
                                                    parent=True),
                            q=True,
                            ws=True,
                            t=True)
        if len(rigids) > 1:
            t2 = maya.cmds.xform(maya.cmds.listRelatives(rigids[1],
                                                         fullPath=True,
                                                         parent=True),
                                 q=True,
                                 ws=True,
                                 t=True)
            t = [(t[0] + t2[0]) * 0.5, (t[1] + t2[1]) * 0.5,
                 (t[2] + t2[2]) * 0.5]

        constraintT = maya.cmds.listRelatives(constraint, parent=True)
        maya.cmds.xform(constraintT, ws=True, t=t)

        ret = [constraint]
        # If command echoing is off, echo this short line.
        if (not maya.cmds.commandEcho(query=True, state=True)):
            print(
                "RigidBodyConstraint.CreateRigidBodyConstraint.executeCommandCB()"
            )
            print "// Result: %s //" % constraint

        return ret
예제 #11
0
def createRagdoll(rootJoint=None,
                  angularDamping=DEFAULT_ANGULAR_DAMPING,
                  angularSoftness=DEFAULT_ANGULAR_SOFTNESS,
                  angularRestitution=DEFAULT_ANGULAR_RESTITUTION,
                  capsuleBoneRatio=DEFAULT_CAPSULE_LENGTH,
                  capsuleRadiusRatio=DEFAULT_CAPSULE_RADIUS,
                  capsuleMass=DEFAULT_CAPSULE_MASS,
                  jointNameSeparator=DEFAULT_NAME_SEPARATOR):
    """
	Creates a ragdoll of capsules joined by constraints, that matches
	the skeleton starting from the joint named by rootJoint. If no
	root is specified, the current selection is used.
	"""
    nodesToVisit = deque(_getNodesToVisit(rootJoint))

    if not nodesToVisit or len(nodesToVisit) < 1:
        maya.OpenMaya.MGlobal.displayError(
            maya.stringTable['y_Ragdoll.kCreateRagdollSelectJoint'])
        return

    ragdollRootNode = maya.cmds.createNode('transform',
                                           name="Ragdoll#",
                                           skipSelect=True)

    currentJoint = None
    while (len(nodesToVisit) > 0):
        logger.debug( maya.stringTable[ 'y_Ragdoll.kStartingIterCurrJoint'  ] \
               % (currentJoint, nodesToVisit) )
        currentJoint = nodesToVisit.popleft()
        # NOTE: assumes joints are directly connected to each other
        try:
            parentJoint = _firstParent(currentJoint)
            if (not _isJoint(parentJoint)):
                parentJoint = None
        except:
            parentJoint = None
        # end-try

        logger.debug(maya.stringTable['y_Ragdoll.kVisiting2'] % currentJoint)
        (rbAXform, rbA) = _getRagdollCapsule(ragdollRootNode, parentJoint,
                                             currentJoint, jointNameSeparator)
        childJoints = _getChildren(currentJoint, type="joint")
        nodesToVisit.extend(childJoints)

        prevChildJoint = None
        for childJoint in childJoints:
            # Here's what we're working with within this loop:
            #
            # parent		   current		   child
            #  joint --[rbA]--> joint --[rbB]--> joint
            (rbBXform, rbB) \
             = _createCapsule( currentJoint, childJoint, False,
                   eBodyType.kDynamicRigidBody, capsuleMass,
                   capsuleBoneRatio, capsuleRadiusRatio,
                   "%s%s%s" % (_name(currentJoint),
                      jointNameSeparator,
                      _name(childJoint)) )
            rbBXform = _setParent(rbBXform, ragdollRootNode)
            rbBName = None
            if (rbB is not None):
                rbBName = _getChildren(rbBXform,
                                       type='bulletRigidBodyShape')[0]
            rbBXformName = None
            if (rbBXform is not None): rbBXformName = _longName(rbBXform)

            # figure out what to anchor this rigid body to
            if (rbA is None and prevChildJoint is not None):
                # prevChildJoint implies that a sibling capsule was
                # created in a previous iteration, which this capsule
                # can be constrained to.
                (sibXform, sib) \
                 = _getRagdollCapsule( ragdollRootNode, currentJoint, prevChildJoint,
                        jointNameSeparator )
                rbAnchorName = _longName(sib)
            elif (rbA is not None):
                rbAnchorName = _longName(rbA)
            else:
                # NOTE: don't create constraints without an anchor, or
                # else the ragdoll will end up constrained to the world.
                rbAnchorName = None
            # end-if

            if (rbAnchorName is not None):
                logger.info( maya.stringTable[ 'y_Ragdoll.kCreatingConstr'  ] \
                      % (rbAnchorName, rbB) )
                # "constraint" abbreviated "constr"
                constrName = _createRigidBodyConstraint( \
                     constraintType=eConstraintType.kRBConstraintSixDOF,
                     rigidBodyA=rbAnchorName,
                     rigidBodyB=rbBName,
                     parent=None )[0]
                constrNode = constrName
                constrXformNode = _firstParent(constrNode)

                # configure the transform
                constrXformNode = maya.cmds.rename(
                    constrXformNode, "constraint_%s" % _name(currentJoint))
                constrXformNode = _setParent(constrXformNode, ragdollRootNode)
                constrNode = _getChildren(
                    constrXformNode, type='bulletRigidBodyConstraintShape')[0]
                _setTranslation(constrXformNode,
                                _getTranslation(currentJoint, space="world"))
                _setRotation(constrXformNode,
                             _getRotation(currentJoint, space="world"))

                # configure the constraint
                _setAttr(constrNode, 'angularDamping', angularDamping)
                _setAttr(constrNode, 'angularSoftness', angularSoftness)
                _setAttr(constrNode, 'angularRestitution', angularRestitution)

                # lock the linear motion, to behave like a point constraint
                _setAttr(constrNode,'linearConstraintX', \
                 eConstraintLimitType.kRBConstraintLimitLocked )
                _setAttr(constrNode,'linearConstraintY', \
                 eConstraintLimitType.kRBConstraintLimitLocked )
                _setAttr(constrNode,'linearConstraintZ', \
                 eConstraintLimitType.kRBConstraintLimitLocked )

                # set the rotational limits to match the joint
                _applyJointLimits(currentJoint, constrNode)
            # end-if

            prevChildJoint = childJoint
        # end-for
    # end-while

    maya.cmds.select(ragdollRootNode, replace=True)
예제 #12
0
def _createCapsule(currentJoint,
                   childJoint,
                   bAttachToJoint=True,
                   bodyType=eBodyType.kKinematicRigidBody,
                   mass=0.0,
                   boneLengthRatio=DEFAULT_CAPSULE_LENGTH,
                   lengthRadiusRatio=DEFAULT_CAPSULE_RADIUS,
                   transformName=None):
    """
	Create a capsule collider around the bone from currentJoint to
	childJoint. If bAttachToJoint is True, the capsule will be
	parented to the current joint, otherwise it will be created at the
	top level of the scene. BodyType and mass can be specified, and
	transform name can be used to specify the name of the new
	top-level rigid body transform.

	This implementation is based on the current rigid body hierarchy,
	which looks like:

	rbXform
	  --> bulletXform
			--> rbShape (capsule)

	Returns (rbXform, rbShape)
	"""
    if (transformName is None):
        transformName = '%s#' % RB_XFORM_PREFIX

    if (bAttachToJoint):
        parent = currentJoint
    else:
        parent = None

    rbXform = maya.cmds.createNode('transform',
                                   name=transformName,
                                   parent=parent,
                                   skipSelect=True)

    # these values will work when adding capsules to a joint hierarchy
    boneVector = _getTranslation(childJoint)
    center = _vector(_vectorLength(*boneVector) * .5, 0, 0)
    worldOffset = _vector(0, 0, 0)

    if (not bAttachToJoint):
        # if this capsule won't be inheriting the transform from the
        # parent joint, these values need to be adjusted for world-space
        worldOffset = _getTranslation(currentJoint, space="world")
        boneVector  = _getTranslation( childJoint, space="world") \
              - _getTranslation(currentJoint, space="world")
        center = _vector(_vectorLength(*boneVector) * .5, 0,
                         0)  # rotation is from the x axis.
    # end-if

    rotateQuat = _quaternion(_vector(1, 0, 0), boneVector)
    rotateAngles = rotateQuat.asEulerRotation()

    _setRotation(rbXform, rotateAngles)
    _setTranslation(rbXform, worldOffset)

    logger.info(maya.stringTable['y_Ragdoll.kAddingRB'] % rbXform)
    (rbParentName, rbName) = _createRigidBody( \
         transformName=_longName(rbXform),
         colliderShapeType=eShapeType.kColliderCapsule,
         axis=eAxisType.kXAxis,
         ignoreShape=True,
         bAttachSelected=False )
    rbNode = rbName
    _setAttr(rbNode, 'bodyType', bodyType)
    _setAttr(rbNode, 'mass', mass)
    _setAttr(rbNode, 'centerOfMass', center)
    capsuleRadius = _calcCapsuleRadius(currentJoint, childJoint,
                                       lengthRadiusRatio)
    _setAttr(rbNode, 'length', \
     max(0.0,
      math.fabs( _vectorLength(*boneVector) * boneLengthRatio)
      - capsuleRadius) )
    _setAttr(rbNode, 'radius', capsuleRadius)

    return (rbXform, rbNode)