def extractFromRigidSet( *args, **kw ): rbSets = _findRigidSetsFromSelection() memberObjects = set(kw['members'] if kw.has_key('members') else maya.cmds.ls(sl=True, type='transform')) for rbSet in rbSets: extractObjects = memberObjects.intersection(set(maya.cmds.sets( rbSet, q=True ))) if len(extractObjects): CreateRigidSet.removeFromRigidSet([rbSet], members=list(extractObjects)) # read attributes from rigidset rbInitialState = _getInitialState(rbSet) kwArgs = {'bodyType':eBodyType.kDynamicRigidBody, 'autoFit':True, 'bAttachSelected':False} for attr, mappedAttr in CreateRigidSet.extractableAttrs.iteritems(): attrVal =_getAttr(rbInitialState,attr) # getAttr returns [()] for vector values if type(attrVal) in [types.ListType] and type(attrVal[0]) in [types.TupleType]: attrVal = attrVal[0] kwArgs[mappedAttr]=attrVal for object in extractObjects: kwArgs['transformName'] = object rtn = CreateRigidBody().command(**kwArgs) BulletUtils.setAsIntermediateObjects( extractObjects, 0 )
def UnapplySchema(self, dgModifier): if self.GetMayaObjectForSchema() is None: # Already unapplied? return False path = om.MDagPath.getAPathTo(self.mayaObject) if not path or not path.pop(): return False BulletUtils.checkPluginLoaded() BulletUtils.removeBulletObjectsFromList([path.fullPathName()]) return self.GetMayaObjectForSchema() is None
def clearRigidSets( *args, **kw ): rbSets = _findRigidSetsFromSelection(excludeTransforms=True) if len(rbSets)==0: OpenMaya.MGlobal.displayError(maya.stringTable[ 'y_RigidBody.kErrorClearNoRigidSetSelected' ]) return for rbSet in rbSets: members = maya.cmds.sets( rbSet, q=True ) maya.cmds.sets( e=True, clear=rbSet ) BulletUtils.setAsIntermediateObjects(members,0) return rbSets
def deleteRigidSets( *args, **kw ): from BulletUtils import removeBulletObjectsFromList rbSets = _findRigidSetsFromSelection(excludeTransforms=True) if len(rbSets)==0: OpenMaya.MGlobal.displayError(maya.stringTable[ 'y_RigidBody.kErrorDeleteNoRigidSetSelected' ]) return for rbSet in rbSets: members = maya.cmds.sets( rbSet, q=True ) BulletUtils.setAsIntermediateObjects(members,0) removeBulletObjectsFromList(list(rbSets)) return
def _ApplyBulletSchema(mayaShape): """Creates a bullet simulation containing the "mayaShape", this is obviously demo code, so we will not even try to add the shape to an existing simluation.""" if _GetBulletShape(mayaShape) is not None: return True path = om.MDagPath.getAPathTo(mayaShape) if not path or not path.pop(): return False BulletUtils.checkPluginLoaded() RigidBody.CreateRigidBody.command(transformName=path.fullPathName(), bAttachSelected=False) return True
def removeFromRigidSet( *args, **kw ): rbSets = args[0] if len(args) else _findRigidSetsFromSelection(excludeTransforms=True) removeObjects = kw['members'] if kw.has_key('members') else maya.cmds.ls(sl=True, type='transform') excludeSets = kw['excludeSets'] if kw.has_key('excludeSets') else [] if len(rbSets)==0: rbSets = _findRigidSetsFromMembers(removeObjects) # only remove from sets not in excludeSets rbSets = set(rbSets).difference(set(excludeSets)) for rbSet in rbSets: BulletUtils.setAsIntermediateObjects( removeObjects, 0 ) maya.cmds.sets( removeObjects, e=True, remove=rbSet ) return removeObjects
def paintSoftBodyVertexProperty(vertexProperty, softbody=None): '''Perform paint action on SoftBody node ''' # if mesh not specified, then get from current selection if softbody == None: softbodies = BulletUtils.getSelectedSoftBodies() if (softbodies != None) and (len(softbodies) > 0): softbody = softbodies[0] if len(softbodies) > 1: maya.cmds.warning( maya.stringTable['y_SoftBody.kMultipleBulletUsingFirst']) if softbody != None: maya.mel.eval( 'source "artAttrCreateMenuItems"; artSetToolAndSelectAttr("artAttrCtx", "mesh.%s.%s")' % (softbody, vertexProperty)) # If the soft body does not have any vertices being mapped, initialize the map to 1.0. vals = maya.cmds.getAttr(softbody + "." + vertexProperty) if (vals == None): ctx = maya.cmds.currentCtx() maya.cmds.artAttrCtx(ctx, edit=True, value=1.0) maya.cmds.artAttrCtx(ctx, edit=True, clear=True) else: maya.OpenMaya.MGlobal.displayError( maya.stringTable['y_SoftBody.kNoBulletSoftbodyshape'])
def command( **kwargs ): """ main entry point for command """ # To create an empty set pass an empty list for the objects # argument args=[] sl=True if kwargs.has_key('sl'): sl = kwargs['sl'] kwargs.pop('sl') hideShape = False if kwargs.has_key('hideShape'): hideShape = kwargs['hideShape'] kwargs.pop('hideShape') if not sl: args.append([]) objects = _getSelectedTransforms() if sl else [] # ensure exclusive if len(objects): rbSets = _findRigidSetsFromMembers(objects) if len(rbSets): CreateRigidSet.removeFromRigidSet( rbSets, members=objects) result = maya.cmds.bulletRigidSets( *args, **kwargs ) ''' return result from command ''' if result: # hide source objects if hideShape: BulletUtils.setAsIntermediateObjects( objects, 1, deferred=True ) # If command echoing is off, echo this short line. if (not maya.cmds.commandEcho(query=True, state=True)): print "// Result: %s //" % (string.join(result, " ")) return result
def addToRigidSet( *args, **kw ): rbSets = _findRigidSetsFromSelection(excludeTransforms=True) if len(rbSets)>1: OpenMaya.MGlobal.displayError(maya.stringTable['y_RigidBody.kAmbiguousAddToSet' ]) return if len(rbSets)==0: OpenMaya.MGlobal.displayError(maya.stringTable['y_RigidBody.kNoRigidSetToAddSelected' ]) return addObjects = kw['members'] if kw.has_key('members') else maya.cmds.ls(sl=True, type='transform') hideShape = kw['hideShape'] if kw.has_key('hideShape') else True # filter out objects with rigid body shapes filteredAddObjects = [] bulletObjects = [] for object in addObjects: if BulletUtils.getRigidBodyFromTransform(object): OpenMaya.MGlobal.displayInfo(maya.stringTable['y_RigidBody.kAlreadyRigidBody' ].format(object)) bulletObjects.append(object) else: filteredAddObjects.append(object) # ensure exclusive if len(filteredAddObjects): CreateRigidSet.removeFromRigidSet(members=filteredAddObjects, excludeSets=rbSets) # remove bullet rigid shape from objects if len(bulletObjects): BulletUtils.removeBulletObjectsFromList(bulletObjects) filteredAddObjects.extend( bulletObjects ) if len(filteredAddObjects): maya.cmds.sets( filteredAddObjects, e=True, addElement=rbSets[0] ) if hideShape: BulletUtils.setAsIntermediateObjects( filteredAddObjects, 1, deferred=True )
def command_shape(**kwargs): returnedTransforms = [] shapes = kwargs['shapes'] # Make sure the list doesn't contain any bullet objects. shapes = BulletUtils.verifySelectionNotBullet(shapes, False) for s in shapes: shapeT = _firstParent(s) # Verify collision shape type is valid. if (maya.cmds.nodeType(s) != 'mesh'): if (kwargs.has_key('colliderShapeType')): shapeType = kwargs['colliderShapeType'] if (shapeType == eShapeType.kColliderHull) or (shapeType == eShapeType.kColliderMesh): kwargs['colliderShapeType'] = eShapeType.kColliderBox kwargs['centerOfMass'] = centerOfMass(shapeT) # Create rigidbody kwargs['bAttachSelected']=False kwargs['transformName']=shapeT rbTs = CreateRigidBody.doCommand(**kwargs) rbShape = _longName(rbTs[1]) if kwargs.has_key('autoFit') and kwargs['autoFit']: (radius, length, ex, ey, ez, cx, cy, cz) = refitCollisionShape(rbShape, s) kwargs['radius'] = radius kwargs['length'] = length kwargs['extents'] = [ex, ey, ez] kwargs['centerOfMass'] = [cx, cy, cz] returnedTransforms.append(rbTs[0]) returnedTransforms.append(rbTs[1]) # Connects if (maya.cmds.nodeType(s) == 'mesh'): _connectAttr( _attr(s,"outMesh"), _attr(rbShape, "inMesh")) return returnedTransforms
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 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 testComplexAdaptation(self): """Test that we can adapt a bullet simulation""" mayaUsdLib.SchemaApiAdaptor.Register(TestBulletMassShemaAdaptor, "shape", "PhysicsMassAPI") mayaUsdLib.SchemaApiAdaptor.Register(TestBulletRigidBodyShemaAdaptor, "shape", "PhysicsRigidBodyAPI") # Build a scene (and exercise the adaptor in a freeform context) cmds.file(f=True, new=True) s1T = cmds.polySphere()[0] cmds.loadPlugin("bullet") if not BulletUtils.checkPluginLoaded(): return rbT, rbShape = RigidBody.CreateRigidBody().command( autoFit=True, colliderShapeType=RigidBody.eShapeType.kColliderSphere, meshes=[s1T], radius=1.0, mass=5.0, centerOfMass=(0.9, 0.8, 0.7)) # See if the plugin adaptor can read the bullet shape under the mesh: sl = om.MSelectionList() sl.add(s1T) dagPath = sl.getDagPath(0) dagPath.extendToShape() adaptor = mayaUsdLib.Adaptor(dagPath.fullPathName()) self.assertEqual(adaptor.GetUsdType(), Tf.Type.FindByName('UsdGeomMesh')) # NOTICE: PhysicsRigidBodyAPI is not in the list because that API is # supported only on export!!! self.assertEqual(adaptor.GetAppliedSchemas(), ['PhysicsMassAPI']) physicsMass = adaptor.GetSchemaByName("PhysicsMassAPI") self.assertEqual(physicsMass.GetName(), "PhysicsMassAPI") massAttributes = set([ 'physics:centerOfMass', 'physics:density', 'physics:diagonalInertia', 'physics:mass', 'physics:principalAxes' ]) self.assertEqual(set(physicsMass.GetAttributeNames()), massAttributes) bulletAttributes = set(['physics:centerOfMass', 'physics:mass']) self.assertEqual(set(physicsMass.GetAuthoredAttributeNames()), bulletAttributes) bulletMass = physicsMass.GetAttribute('physics:mass') self.assertAlmostEqual(bulletMass.Get(), 5.0) bulletMass.Set(12.0) bulletCenter = physicsMass.GetAttribute('physics:centerOfMass') bulletCenter.Set(Gf.Vec3f(3, 4, 5)) sl = om.MSelectionList() sl.add(s1T) bulletPath = sl.getDagPath(0) bulletPath.extendToShape(1) massDepFn = om.MFnDependencyNode(bulletPath.node()) plug = om.MPlug(bulletPath.node(), massDepFn.attribute("mass")) self.assertAlmostEqual(plug.asFloat(), 12.0) # Create an untranslated attribute: usdDensity = physicsMass.CreateAttribute('physics:density') usdDensity.Set(33.0) self.assertAlmostEqual(usdDensity.Get(), 33.0) # This will result in a dynamic attribute on the bulletShape: plug = massDepFn.findPlug("USD_ATTR_physics_density", True) self.assertAlmostEqual(plug.asFloat(), 33.0) bulletAttributes.add('physics:density') self.assertEqual(set(physicsMass.GetAuthoredAttributeNames()), bulletAttributes) physicsMass.RemoveAttribute('physics:density') bulletAttributes.remove('physics:density') self.assertEqual(set(physicsMass.GetAuthoredAttributeNames()), bulletAttributes) # Add some animation: cmds.setKeyframe(bulletPath, at="mass", t=0, v=3.0) cmds.setKeyframe(bulletPath, at="mass", t=10, v=30.0) # Modify the velocity so it can be exported to the RBD Physics schema. cmds.setKeyframe(bulletPath, at="initialVelocityX", t=0, v=5.0) cmds.setKeyframe(bulletPath, at="initialVelocityX", t=10, v=50.0) cmds.setKeyframe(bulletPath, at="initialVelocityY", t=0, v=6.0) cmds.setKeyframe(bulletPath, at="initialVelocityY", t=10, v=60.0) cmds.setKeyframe(bulletPath, at="initialVelocityZ", t=0, v=7.0) cmds.setKeyframe(bulletPath, at="initialVelocityZ", t=10, v=70.0) # Try applying the schema on a new sphere: s2T = cmds.polySphere()[0] sl.add(s2T) dagPath = sl.getDagPath(1) dagPath.extendToShape() adaptor = UsdMaya.Adaptor(dagPath.fullPathName()) physicsMass = adaptor.ApplySchemaByName("PhysicsMassAPI") self.assertEqual(physicsMass.GetName(), "PhysicsMassAPI") self.assertEqual(adaptor.GetUsdType(), Tf.Type.FindByName('UsdGeomMesh')) self.assertEqual(adaptor.GetAppliedSchemas(), ['PhysicsMassAPI']) usdDensity = physicsMass.CreateAttribute('physics:density') usdDensity.Set(33.0) # Export, but without enabling Bullet: usdFilePath = os.path.abspath('UsdExportSchemaApiTest_NoBullet.usda') cmds.mayaUSDExport(mergeTransformAndShape=True, file=usdFilePath) # Check that there are no Physics API schemas exported: stage = Usd.Stage.Open(usdFilePath) for i in (1, 2): spherePrim = stage.GetPrimAtPath( '/pSphere{0}/pSphereShape{0}'.format(i)) self.assertFalse( "PhysicsMassAPI" in spherePrim.GetAppliedSchemas()) schemasToExport = ["PhysicsMassAPI", "PhysicsRigidBodyAPI"] # Export, with Bullet: usdFilePath = os.path.abspath('UsdExportSchemaApiTest_WithBullet.usda') cmds.mayaUSDExport(mergeTransformAndShape=True, file=usdFilePath, apiSchema=schemasToExport, frameRange=(1, 10)) # Check that Physics API schemas did get exported: stage = Usd.Stage.Open(usdFilePath) values = [ ("physics:centerOfMass", (Gf.Vec3f(3, 4, 5), Gf.Vec3f(0, 0, 0))), ("physics:mass", (3.0, 1.0)), ("physics:density", (None, 33.0)), ] for i in (1, 2): spherePrim = stage.GetPrimAtPath( '/pSphere{0}/pSphereShape{0}'.format(i)) self.assertTrue("PhysicsMassAPI" in spherePrim.GetAppliedSchemas()) for n, v in values: if v[i - 1]: a = spherePrim.GetAttribute(n) self.assertEqual(a.Get(), v[i - 1]) if i == 1: # Is mass animated? a = spherePrim.GetAttribute("physics:mass") self.assertEqual(a.Get(10), 30) # This got exported even though invisible in interactive: self.assertTrue( "PhysicsRigidBodyAPI" in spherePrim.GetAppliedSchemas()) a = spherePrim.GetAttribute("physics:velocity") if i == 1: self.assertEqual(a.Get(0), (5, 6, 7)) self.assertEqual(a.Get(10), (50, 60, 70)) numberOfExportedKeys = len(a.GetTimeSamples()) # Try unapplying the schema: adaptor.UnapplySchemaByName("PhysicsMassAPI") self.assertEqual(adaptor.GetAppliedSchemas(), []) # Test import of USDPhysics without job context: cmds.file(new=True, force=True) cmds.mayaUSDImport(f=usdFilePath) sl = om.MSelectionList() # pSphereShape1 is a transform, since the bullet shape prevented merging the mesh and the # transform. The shape will be pSphereShape1Shape... sl.add("pSphereShape1") bulletPath = sl.getDagPath(0) # No bullet shape since we did not put Bullet as jobContext self.assertEqual(bulletPath.numberOfShapesDirectlyBelow(), 1) cmds.file(new=True, force=True) cmds.mayaUSDImport(f=usdFilePath, apiSchema=schemasToExport, readAnimData=True) sl = om.MSelectionList() sl.add("pSphereShape1") bulletPath = sl.getDagPath(0) # Finds bullet shape since we did put Bullet as jobContext self.assertEqual(bulletPath.numberOfShapesDirectlyBelow(), 2) # The bullet shape has animated mass and initial velocity since we read the animation. bulletPath.extendToShape(1) massDepFn = om.MFnDependencyNode(bulletPath.node()) for attrName in ("mass", "initialVelocityX", "initialVelocityY", "initialVelocityZ"): plug = om.MPlug(bulletPath.node(), massDepFn.attribute(attrName)) self.assertTrue(plug.isConnected) fcurve = oma.MFnAnimCurve(plug.source().node()) self.assertEqual(fcurve.numKeys, numberOfExportedKeys)
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 ]
def command(*args, **kwargs ): ret = [] transformNames = [] if (kwargs.has_key('bAttachSelected') and not kwargs['bAttachSelected']): if kwargs.has_key('transformName'): transformNames = [kwargs['transformName']] else: # Make sure the list doesn't contain any bullet objects. transformNames = _getSelectedTransforms() if (kwargs.has_key('ignoreShape') and kwargs['ignoreShape']): shapes = [] else: shapes = _getSelectedShapes(transformNames) # remove transforms already processed as shapes if shapes and transformNames and len(transformNames): filteredTransformNames = [] for transformName in transformNames: ts = _getSelectedShapes(transformName) ts = ts if ts else [] if len(ts)==0 or len(set(ts).intersection(shapes))==0: filteredTransformNames.append(transformName) transformNames = filteredTransformNames # if no shapes and no transforms create bullet object without node if (not transformNames or len(transformNames)==0) and (not shapes or len(shapes) == 0): transformNames = [None] if shapes and len(shapes): kwargs['shapes'] = shapes rbShapes = CreateRigidBody.command_shape(**kwargs) ret += rbShapes if rbShapes else [] if len(transformNames): # Create rigid bodies without an associated shape # Verify collision shape type is valid. if (kwargs.has_key('colliderShapeType')): shapeType = kwargs['colliderShapeType'] if (shapeType == eShapeType.kColliderHull) or (shapeType == eShapeType.kColliderMesh): kwargs['colliderShapeType'] = eShapeType.kColliderBox for transformName in transformNames: # Make sure the transformName doesn't contain any bullet objects. if transformName and BulletUtils.getRigidBodyFromTransform(transformName): OpenMaya.MGlobal.displayWarning(maya.stringTable['y_RigidBody.kAlreadyBulletObject2' ].format(transformName) ) continue kwargs['transformName'] = transformName rbShapes = CreateRigidBody.doCommand(*args, **kwargs) ret += rbShapes rbShape = _longName(rbShapes[1]) if transformName and kwargs.has_key('autoFit') and kwargs['autoFit']: (radius, length, ex, ey, ez, cx, cy, cz) = refitCollisionShape(rbShape, transform=transformName) kwargs['radius'] = radius kwargs['length'] = length kwargs['extents'] = [ex, ey, ez] kwargs['centerOfMass'] = [cx, cy, cz] if len(ret): maya.cmds.select(ret, r=True) # If command echoing is off, echo this short line. if (not maya.cmds.commandEcho(query=True, state=True)): print("RigidBody.CreateRigidBody().executeCommandCB()") print "// Result: %s //" % string.join(ret, " ") return ret
# GenerateFractureLogs # Script to generate fracture points in the Log scene import maya.cmds as cmds import random import math import maya.app.mayabullet.BulletUtils as BulletUtils import maya.app.mayabullet.RigidBody as RigidBody BulletUtils.checkPluginLoaded() # Get object to be shattered cmds.select(['log1','log2','log3']) selected = cmds.ls(sl=True, transforms=True) objCounter = 0 for obj in selected: print(obj) # Get center point of collision (in our case center of the logs) com = cmds.objectCenter(obj, gl=True) numPoints = 30 fractureRadius = 3 thickness = 1 # Will get divided by 2 height = cmds.getAttr(obj + '.translateY') transX = cmds.getAttr(obj + '.translateX') rotY = cmds.getAttr(obj + '.rotateY') voroX = [] voroY = [] voroZ = [] #print(height)
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