Esempio n. 1
0
	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 )
Esempio n. 2
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
Esempio n. 3
0
	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
Esempio n. 4
0
	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
Esempio n. 5
0
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
Esempio n. 6
0
	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
Esempio n. 7
0
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'])
Esempio n. 8
0
	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
Esempio n. 9
0
	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 )
Esempio n. 10
0
	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
Esempio n. 11
0
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)
Esempio n. 12
0
    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
Esempio n. 13
0
    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)
Esempio n. 14
0
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
Esempio n. 15
0
	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 ]
Esempio n. 16
0
	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
Esempio n. 17
0
# 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)
    
Esempio n. 18
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