def setSoftBodyPerParticleBendResistance(newValue=None): # Store off original selection origSel = maya.cmds.ls(sl=True) #Get softBody for verts maya.cmds.select(maya.cmds.listConnections('.worldMesh', d=1, sh=1, type='bulletSoftBodyShape'), add=True) maya.cmds.select(maya.cmds.listConnections(".inMesh", s=1, sh=1, type='bulletSoftBodyShape'), add=True) softBodies = maya.cmds.ls(sl=True, dag=True, type='bulletSoftBodyShape') if len(softBodies) != 1: maya.cmds.select(origSel, r=True) maya.OpenMaya.MGlobal.displayError( _loadUIString('kSelectVertsAttached')) return # If $newValue is -1, then bring up the prompt if (newValue == None): okBut = _loadUIString('kOk') cancelBut = _loadUIString('kCancel') result = maya.cmds.promptDialog( title=_loadUIString('kBulletSoftbodyPerParticleSet'), message=maya. stringTable['y_SoftBody.kEnterPerParticleBendResistance'], button=[okBut, cancelBut], defaultButton=okBut, cancelButton=cancelBut, dismissString=cancelBut) if result != okBut: maya.cmds.select(origSel, r=True) return newValue = float(maya.cmds.promptDialog(query=True, text=True)) if newValue < 0.0: maya.cmds.select(origSel, r=True) maya.OpenMaya.MGlobal.displayError(maya.stringTable[ 'y_SoftBody.kCannotHaveANegativeValueForBendResistance']) return softBody = softBodies[0] # Get ids ids = BulletUtils.extractVertexIds( maya.cmds.ls(sl=True, flatten=True, type='float3')) # Set particleBendResistance if len(ids) > 0: # get the current array of values attr = softBody + ".particleBendResistance" vals = maya.cmds.getAttr(attr) # create the array if it doesn't exist if (vals == None): mesh = maya.cmds.listConnections(softBody + '.inWorldMesh', d=1, sh=1) maya.cmds.select(mesh, r=True) selList = maya.OpenMaya.MSelectionList() maya.OpenMaya.MGlobal.getActiveSelectionList(selList) path = maya.OpenMaya.MDagPath() comp = maya.OpenMaya.MObject() selList.getDagPath(0, path, comp) path.extendToShape() meshFn = maya.OpenMaya.MFnMesh(path) count = meshFn.numVertices() vals = [1] * count # override value for selected ids for id in ids: vals[id] = newValue # set the array of values maya.cmds.setAttr(attr, vals, type='doubleArray') else: maya.OpenMaya.MGlobal.displayError( _loadUIString('kSelectVertsAttached')) # Set back original selection maya.cmds.select(origSel, r=True)
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