def command( meshes=None, name='bulletSoftBodyShape#', # Attrs generateBendConstraints=None, selfCollision=None, bendResistance=None, linearStiffness=None, friction=None, damping=None, pressure=None, collisionMargin=None, positionIterations=None, #poseMatching=None, #enablePoseMatching=None, preserveSourceMesh=None, singleTransform=None, **kwargs): '''Create a bulletSoftBody from specified mesh. ''' # Explicitly list the names of settable attributes iterated over below settableAttrs = [ 'generateBendConstraints', 'selfCollision', 'bendResistance', 'linearStiffness', 'friction', 'damping', 'pressure', 'collisionMargin', 'positionIterations', #'poseMatching', #'enablePoseMatching', ] # Make a boolean value that is easier to read in code singleTransform = singleTransform != False # Get list of meshes from selection if not passed in if (meshes == None): maya.cmds.select(maya.cmds.listRelatives(shapes=True, fullPath=True), add=True) meshes = maya.cmds.ls(sl=True, type='mesh', long=True) # Make sure the selection doesn't contain any bullet objects. BulletUtils.verifySelectionNotBullet(meshes) returnedNodes = [] # Sanity Checking if len(meshes) == 0: maya.OpenMaya.MGlobal.displayError( maya.stringTable['y_SoftBody.kSelectMesh']) return returnedNodes # Loop over meshes and create soft bodies for mesh in meshes: meshT = maya.cmds.listRelatives([mesh], parent=True, fullPath=True)[0] # Duplicate mesh and connect in history # Alternate: use a stub func like polyReduce -replaceOriginal 0 -percentage 100 -nodeState 1 -name "stubPolyMod"; meshCopyT = maya.cmds.polyDuplicateAndConnect(mesh)[0] meshCopyShape = maya.cmds.listRelatives(meshCopyT, s=True, fullPath=True)[0] if not singleTransform: maya.cmds.setAttr((meshCopyT + ".t"), 0, 0, 0) # zero out the transform since get values from WorldSpace maya.cmds.setAttr((meshCopyT + ".r"), 0, 0, 0) # zero out the transform since get values from WorldSpace maya.cmds.setAttr((meshCopyT + ".s"), 1, 1, 1) # zero out the transform since get values from WorldSpace maya.cmds.setAttr((meshCopyT + ".inheritsTransform"), 0) # Create softbody shape # NOTE: If plugin not loaded, then sbShape will return unknown nodetype # and listRelatives will not work as expected sbShape = maya.cmds.createNode('bulletSoftBodyShape', name=name) sbT = maya.cmds.listRelatives([sbShape], parent=True, fullPath=True)[0] # Reparent body shape under it maya.cmds.parent(sbShape, meshT, r=True, s=True) maya.cmds.delete(sbT) sbT = meshT # Create Solver (proto) sol = BulletUtils.getSolver() # Connect maya.cmds.connectAttr((mesh + ".worldMesh"), (sbShape + ".inWorldMesh")) maya.cmds.connectAttr((sol + ".outSolverInitialized"), (sbShape + ".solverInitialized")) maya.cmds.connectAttr((sbShape + ".outSoftBodyData"), (sol + ".softBodies"), na=True) maya.cmds.connectAttr((sol + ".outSolverUpdated"), (sbShape + ".solverUpdated")) maya.cmds.connectAttr((sbShape + ".outSolvedMesh"), (meshCopyShape + ".inMesh"), f=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((sol + ".startTime"), (sbShape + ".startTime")) maya.cmds.connectAttr((sol + ".currentTime"), (sbShape + ".currentTime")) # 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' % (sbShape, k), *v) # covers float3 cases else: maya.cmds.setAttr('%s.%s' % (sbShape, k), v) # Additional Actions if (preserveSourceMesh == False): maya.cmds.setAttr((mesh + '.intermediateObject'), True) # Alternate: Explicit method #if generateBendConstraints != None: # maya.cmds.setAttr((sbShape+'.generateBendConstraints'), generateBendConstraints) #if selfCollision != None: # maya.cmds.setAttr((sbShape+'.selfCollision'), selfCollision) #... if singleTransform: # Move the solved mesh under the same transform as the original mesh maya.cmds.parent(meshCopyShape, meshT, relative=True, shape=True) maya.cmds.reorder(sbShape, back=True) maya.cmds.delete(meshCopyT) maya.cmds.setAttr(sbShape + '.localSpaceOutput', True) else: # We will keep the solved mesh under the new transform # Rename new transform maya.cmds.rename(meshCopyT, meshT + "_Solved") # Update list of returned nodes returnedNodes.append(sbT) returnedNodes.append(sbShape) # If command echoing is off, echo this short line. if (not maya.cmds.commandEcho(query=True, state=True)): print("SoftBody.CreateSoftBody.executeCommandCB()") print "// Result: %s //" % string.join(returnedNodes, " ") # Select and return maya.cmds.select(returnedNodes, add=True) return returnedNodes
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
def createSoftBodyAnchorConstraint(selectedVerts=None): '''Create a bulletSoftConstraint to anchor selected SoftBody vertices to a RigidBody. If no RigidBody is specified, then one will be created and centered on the first selected vertex. ''' # Get list of selected verts if selectedVerts == None: selectedVerts = maya.cmds.ls(sl=True, flatten=True, type='float3') # flattened list if len(selectedVerts) == 0: maya.OpenMaya.MGlobal.displayError(maya.stringTable[ 'y_SoftBodyConstraint.kPleaseSelectASetOfMeshVertsForTheAnchorConstraint'] ) return # extract out the vertex number anchoredVertexIds = BulletUtils.extractVertexIds(selectedVerts) # Get center of selected vertices origTranslate = centroid(selectedVerts) # Get meshshape objs = maya.cmds.listRelatives(selectedVerts[0], parent=True, type='mesh') if objs == None or len(objs) == 0: maya.OpenMaya.MGlobal.displayError(maya.stringTable[ 'y_SoftBodyConstraint.kPleaseSelectMeshVertsForTheAnchorConstraint'] ) return mesh = objs[0] # Get $softbody attached to mesh # First check if output mesh vert selected, so look for incoming connection softbody = "" cons = maya.cmds.listConnections(".inMesh", s=1, sh=1, type='bulletSoftBodyShape') if cons != None and len(cons) == 1: softbody = cons[0] else: # Otherwise, check input mesh to be connected to a softbody cons = maya.cmds.listConnections(".worldMesh[0]", d=1, sh=1, type='bulletSoftBodyShape') if cons != None and len(cons) == 1: softbody = cons[0] if softbody == "": maya.OpenMaya.MGlobal.displayError( maya.stringTable['y_SoftBodyConstraint.kCouldNotDetermineSBShape']) return # Get anchor object anchorCandidates = maya.cmds.ls( sl=True, dag=True, shapes=True) # list all selected shape nodes numCandidates = len(anchorCandidates) if numCandidates == 0: maya.OpenMaya.MGlobal.displayError(maya.stringTable[ 'y_SoftBodyConstraint.kPleaseSelectOneBulletRigidBodyForAnchorConstraint'] ) return # use first object found or first rigid body found anchorConstrError1 = maya.stringTable[ 'y_SoftBodyConstraint.kPleaseSelectOnlyOneObjectForAnchorConstraint1'] anchorConstrError2 = maya.stringTable[ 'y_SoftBodyConstraint.kPleaseSelectOnlyOneObjectForAnchorConstraint2'] anchor = None shape = None rigidbody = None for candidate in anchorCandidates: if maya.cmds.objectType(candidate, isType='bulletRigidBodyShape'): if rigidbody is not None: maya.OpenMaya.MGlobal.displayError(anchorConstrError1) return anchor = candidate rigidbody = candidate else: if shape is not None: maya.OpenMaya.MGlobal.displayError(anchorConstrError2) return anchor = candidate shape = candidate # allow a geometry shape and rigid body shape to be selected as long as the rigid body # shape is connected to the geometry shape and therefore the same 'object'. if shape and rigidbody: rigidbodies = maya.cmds.listConnections(shape, sh=True, type='bulletRigidBodyShape') if rigidbodies is None or rigidbodies[0] != rigidbody: maya.OpenMaya.MGlobal.displayError(anchorConstrError2) return # Create SoftConstraint shape = maya.cmds.createNode("bulletSoftConstraintShape") shapeT = maya.cmds.listRelatives(shape, parent=True)[0] # Create Solver sol = BulletUtils.getSolver() maya.cmds.setAttr((shapeT + ".translate"), *origTranslate) # The logical place for the anchors to be stored is on the constraint node, # but in order to remap the indices when the topology changes we have to # put it on the soft body node and connect it to the constraint node. This # is an array (multi) attribute, one per constraint; each constraint is # itself an int32 array. # Find the new index for the anchor. anchorListAttr = softbody + ".anchors" anchorIndices = maya.cmds.getAttr(anchorListAttr, multiIndices=True) if anchorIndices: anchorNewIndex = anchorIndices[-1] + 1 else: anchorNewIndex = 0 anchorName = "%s[%d]" % (anchorListAttr, anchorNewIndex) # getAttr allocates the new index, then setAttr stores the data, # then connectAttr moves the data to where it's used. maya.cmds.getAttr(anchorName) maya.cmds.setAttr(anchorName, anchoredVertexIds, type='Int32Array') maya.cmds.connectAttr(anchorName, shape + ".indexList") # Connect the simple attributes. maya.cmds.connectAttr((sol + ".startTime"), (shape + ".startTime")) maya.cmds.connectAttr((sol + ".currentTime"), (shape + ".currentTime")) maya.cmds.connectAttr((softbody + ".outSoftBodyData"), (shape + ".softBody")) if (rigidbody): maya.cmds.connectAttr((rigidbody + ".outRigidBodyData"), (shape + ".rigidBody")) else: maya.cmds.connectAttr((anchor + ".worldMatrix"), (shape + ".inWorldMatrix")) maya.cmds.connectAttr((shape + ".outConstraintData"), (sol + ".softConstraints"), na=True) # Return maya.cmds.select(shape) ret = [shape] # If command echoing is off, echo this short line. if (not maya.cmds.commandEcho(query=True, state=True)): print("SoftBodyConstraint.createSoftBodyAnchorConstraint()") print "// Result: %s //" % shape return ret
def doCommand(name='bulletRigidBodyShape#', transformName = None, bAttachSelected = True, ignoreShape = False, hideShape = False, # Attrs colliderShapeType = None, axis = None, length = None, radius = None, extents = None, bodyType = None, initiallySleeping = None, neverSleeps = None, mass = None, linearDamping = None, angularDamping = None, friction = None, restitution = None, initialVelocity = None, initialAngularVelocity = None, impulse = None, torqueImpulse = None, centerOfMass = None, autoFit = None, colliderShapeOffset = None, colliderShapeMargin = None, **kwargs ): '''Create a bulletRigidBody ''' # Explicitly list the names of settable attributes iterated over below # Check for selection being a rigid body already if ( bAttachSelected ): selectedObjs = _getSelectedTransforms() selectedObj = selectedObjs[0] if len(selectedObjs) else None # don't attach a rigid body underneath another one during # creation, it's more likely that the user is invoking # this command multiple times, and the selection is # leftover from a previous invocation. if ( BulletUtils.getRigidBodyFromTransform(selectedObj) is not None ): selectedObj = None else: transformName = selectedObj else: selectedObj = None if not transformName: transformName='' # Create from scratch rbShape = maya.cmds.createNode( "bulletRigidBodyShape", name=name, parent=transformName ) rbXform = _firstParent(rbShape) if not rbXform: OpenMaya.MGlobal.displayError(maya.stringTable[ 'y_RigidBody.kErrorRigidBodyNotCreated' ]) return [ None, None ] # Performance: if we're attaching to an object # make rbShape an visibility so it doesn't draw by default. # NOTE: since the rigid body is not a MPxShape it doesn't # support an intermediateObject attribute. if transformName and hideShape: _setAttr(rbShape, 'visibility', 0) # Create Solver (proto) solver = BulletUtils.getSolver() # 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 CreateRigidBody.settableAttrs and v != None: _setAttr( rbShape, k, v ) # Additional Actions # ******* TODO: Need to enable local transform instead of just worldSpace. Pass in parentMatrix to rigidbody # Store t and r (used below) origTranslate = _getAttr(rbXform, 'translate')[0] origRotate = _getAttr(rbXform,'rotate')[0] # Connect _connectAttr( _attr(rbXform,'worldMatrix'), _attr(rbShape,'inWorldMatrix') ) _connectAttr( _attr(rbXform,'parentInverseMatrix'), _attr(rbShape,'inParentInverseMatrix') ) _connectAttr( _attr(solver,'outSolverInitialized'), _attr(rbShape,'solverInitialized') ) _connectAttr( _attr(solver,'outSolverUpdated'), _attr(rbShape,'solverUpdated') ) _connectAttr( _attr(rbShape,'outRigidBodyData'), _attr(solver,'rigidBodies'), nextAvailable=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 _connectAttr( _attr(solver,'startTime'), _attr(rbShape,'startTime') ) _connectAttr( _attr(solver,'currentTime'), _attr(rbShape,'currentTime') ) _setAttr(rbShape, 'initialTranslate', origTranslate) deg2Rad = 3.14159 / 180 _setAttr(rbShape, 'initialRotateX', origRotate[0] * deg2Rad) _setAttr(rbShape, 'initialRotateY', origRotate[1] * deg2Rad) _setAttr(rbShape, 'initialRotateZ', origRotate[2] * deg2Rad) pairBlend = maya.cmds.createNode( "pairBlend", name= "translateRotate") _setAttr(pairBlend, 'inTranslate1', origTranslate) _setAttr(pairBlend, 'inRotate1', origRotate) _connectAttr( _attr(rbShape, 'outSolvedTranslate'), _attr(pairBlend, 'inTranslate2') ) _connectAttr( _attr(rbShape, 'outSolvedRotate'), _attr(pairBlend, 'inRotate2') ) _connectAttr(_attr(pairBlend, 'outTranslateX'), _attr(rbXform, 'translateX'), force=True) _connectAttr(_attr(pairBlend, 'outTranslateY'), _attr(rbXform, 'translateY'), force=True) _connectAttr(_attr(pairBlend, 'outTranslateZ'), _attr(rbXform, 'translateZ'), force=True) _connectAttr(_attr(pairBlend, 'outRotateX'), _attr(rbXform, 'rotateX'), force=True) _connectAttr(_attr(pairBlend, 'outRotateY'), _attr(rbXform, 'rotateY'), force=True) _connectAttr(_attr(pairBlend, 'outRotateZ'), _attr(rbXform, 'rotateZ'), force=True) _connectAttr(_attr(rbXform, 'isDrivenBySimulation'), _attr(pairBlend,'weight'), force=True) _connectAttr(_attr(rbXform, 'rotatePivot'), _attr(rbShape,'pivotTranslate') ) # ****** TODO: Remove the unused pairBlend weight attrs # Select the rigidBody transform and return the resulting values maya.cmds.select( rbXform, replace=True ) return [ rbXform, rbShape ]