def setSkinWeights( skinCluster, vertJointWeightData ):
	'''
	vertJointWeightData is a list of 2-tuples containing the vertex component name, and a list of 2-tuples
	containing the joint name and weight.  ie it looks like this:
	[ ('someMesh.vtx[0]', [('joint1', 0.25), 'joint2', 0.75)]),
	  ('someMesh.vtx[1]', [('joint1', 0.2), 'joint2', 0.7, 'joint3', 0.1)]),
	  ... ]
	'''

	#convert the vertex component names into vertex indices
	idxJointWeight = []
	for vert, jointsAndWeights in vertJointWeightData:
		idx = int( vert[ vert.rindex( '[' )+1:-1 ] )
		idxJointWeight.append( (idx, jointsAndWeights) )

	#get an MObject for the skin cluster node
	skinCluster = apiExtensions.asMObject( skinCluster )
	skinFn = MFnSkinCluster( skinCluster )

	#construct a dict mapping joint names to joint indices
	jApiIndices = {}
	_tmp = MDagPathArray()
	skinFn.influenceObjects( _tmp )
	for n in range( _tmp.length() ):
		jApiIndices[ str( _tmp[n].node() ) ] = skinFn.indexForInfluenceObject( _tmp[n] )

	weightListP = skinFn.findPlug( "weightList" )
	weightListObj = weightListP.attribute()
	weightsP = skinFn.findPlug( "weights" )

	tmpIntArray = MIntArray()
	baseFmtStr = str( skinCluster ) +'.weightList[%d]'  #pre build this string: fewer string ops == faster-ness!

	for vertIdx, jointsAndWeights in idxJointWeight:

		#we need to use the api to query the physical indices used
		weightsP.selectAncestorLogicalIndex( vertIdx, weightListObj )
		weightsP.getExistingArrayAttributeIndices( tmpIntArray )

		weightFmtStr = baseFmtStr % vertIdx +'.weights[%d]'

		#clear out any existing skin data - and awesomely we cannot do this with the api - so we need to use a weird ass mel command
		for n in range( tmpIntArray.length() ):
			removeMultiInstance( weightFmtStr % tmpIntArray[n] )

		#at this point using the api or mel to set the data is a moot point...  we have the strings already so just use mel
		for joint, weight in jointsAndWeights:
			if weight:
				try:
					infIdx = jApiIndices[ joint ]
				except KeyError:
					try:
						infIdx = jApiIndices[ joint.split( '|' )[0] ]
					except KeyError: continue

				setAttr( weightFmtStr % infIdx, weight )
Beispiel #2
0
def replaceGivenConstraintTarget(constraint, targetToReplace, newTarget):
    '''
	replaces targetToReplace transform on the given constraint with the newTarget transform
	'''
    targetToReplace = apiExtensions.asMObject(targetToReplace)
    newTarget = apiExtensions.asMObject(newTarget)

    #nothing to do if the nodes are the same...
    if apiExtensions.cmpNodes(targetToReplace, newTarget):
        return

    usedTargetIndices = getAttr('%s.target' % constraint, multiIndices=True)
    for idx in usedTargetIndices:
        for attr in attributeQuery('target',
                                   node=constraint,
                                   listChildren=True):
            for connection in listConnections('%s.target[%s].%s' %
                                              (constraint, idx, attr),
                                              p=True,
                                              type='transform',
                                              d=False) or []:
                toks = connection.split('.')
                node = toks[0]

                if apiExtensions.cmpNodes(node, targetToReplace):
                    toks[0] = str(newTarget)
                    connectAttr('.'.join(toks),
                                '%s.target[%s].%s' % (constraint, idx, attr),
                                f=True)
def removeSpace( src, tgt ):
	'''
	removes a target (or space) from a "space switching" object
	'''

	tgts, names = getSpaceTargetsNames( src )
	tgt_mobject = asMObject( tgt )

	name = None
	for index, (aTgt, aName) in enumerate( zip( tgts, names ) ):
		aTgt = asMObject( aTgt )
		if aTgt == tgt_mobject:
			name = aName
			break

	if name is None:
		raise AttributeError( "no such target" )

	delete = False
	if len( tgts ) == 1:
		delete = True

	constraint = findConstraint( src )

	parentAttrOn = findSpaceAttrNode( src )
	space = findSpace( src )

	srcTrigger = Trigger( src )
	cmds = srcTrigger.iterMenus()

	if delete:
		delete( constraint )
		deleteAttr( '%s.parent' % src )
	else:
		constraintType = nodeType( constraint )
		constraintFunc = getattr( cmd, constraintType )
		constraintFunc( tgt, constraint, rm=True )

	for slot, cmdName, cmdStr in srcTrigger.iterMenus():
		if cmdName == ( "parent to %s" % name ):
			srcTrigger.removeMenu( slot )

		#rebuild the parent attribute
		newNames = names[:]
		newNames.pop( index )
		addAttr( '%s.parent' % parentAttrOn, e=True, enumName=':'.join( newNames ) )

	#now we need to update the indicies in the right click command - all targets that were beyond the one we
	#just removed need to have their indices decremented
	for slot, cmdName, cmdStr in srcTrigger.iterMenus():
		if not cmdName.startswith( 'parent to ' ):
			continue

		cmdStrObj = ChangeSpaceCmd( cmdStr )
		cmdIndex = cmdStrObj.getIndex()
		if cmdIndex < index:
			continue

		cmdStrObj = cmdStrObj.setIndex( cmdIndex-1 )
		srcTrigger.setMenuCmd( slot, cmdStrObj )
def removeSpace( src, tgt ):
	'''
	removes a target (or space) from a "space switching" object
	'''

	tgts, names = getSpaceTargetsNames( src )
	tgt_mobject = asMObject( tgt )

	name = None
	for index, (aTgt, aName) in enumerate( zip( tgts, names ) ):
		aTgt = asMObject( aTgt )
		if aTgt == tgt_mobject:
			name = aName
			break

	if name is None:
		raise AttributeError( "no such target" )

	delete = False
	if len( tgts ) == 1:
		delete = True

	constraint = findConstraint( src )

	parentAttrOn = findSpaceAttrNode( src )
	space = findSpace( src )

	srcTrigger = Trigger( src )
	cmds = srcTrigger.iterMenus()

	if delete:
		delete( constraint )
		deleteAttr( '%s.parent' % src )
	else:
		constraintType = nodeType( constraint )
		constraintFunc = getattr( cmd, constraintType )
		constraintFunc( tgt, constraint, rm=True )

	for slot, cmdName, cmdStr in srcTrigger.iterMenus():
		if cmdName == ( "parent to %s" % name ):
			srcTrigger.removeMenu( slot )

		#rebuild the parent attribute
		newNames = names[:]
		newNames.pop( index )
		addAttr( '%s.parent' % parentAttrOn, e=True, enumName=':'.join( newNames ) )

	#now we need to update the indicies in the right click command - all targets that were beyond the one we
	#just removed need to have their indices decremented
	for slot, cmdName, cmdStr in srcTrigger.iterMenus():
		if not cmdName.startswith( 'parent to ' ):
			continue

		cmdStrObj = ChangeSpaceCmd( cmdStr )
		cmdIndex = cmdStrObj.getIndex()
		if cmdIndex < index:
			continue

		cmdStrObj = cmdStrObj.setIndex( cmdIndex-1 )
		srcTrigger.setMenuCmd( slot, cmdStrObj )
Beispiel #5
0
def jointVerts(joint, tolerance=1e-4, onlyVisibleMeshes=True):
    '''
	returns a dict containing data about the verts influences by the given joint - dict keys are mesh names the
	joint affects.  each dict value is a list of tuples containing (weight, idx) for the verts affected by the joint
	'''
    newObjs = []
    meshVerts = {}

    joint = apiExtensions.asMObject(joint)
    jointMDag = joint.dagPath()
    try:
        skins = list(set(listConnections(joint, s=0, type='skinCluster')))
    except TypeError:
        return meshVerts

    MObject = OpenMaya.MObject
    MDagPath = OpenMaya.MDagPath
    MDoubleArray = OpenMaya.MDoubleArray
    MSelectionList = OpenMaya.MSelectionList
    MIntArray = OpenMaya.MIntArray
    MFnSingleIndexedComponent = OpenMaya.MFnSingleIndexedComponent
    for skin in skins:
        skin = apiExtensions.asMObject(skin)
        mfnSkin = MFnSkinCluster(skin)

        mSel = MSelectionList()
        mWeights = MDoubleArray()
        mfnSkin.getPointsAffectedByInfluence(jointMDag, mSel, mWeights)

        for n in range(mSel.length()):
            mesh = MDagPath()
            component = MObject()
            mSel.getDagPath(n, mesh, component)

            #if we only want visible meshes - check to see that this mesh is visible
            if onlyVisibleMeshes:
                if not isNodeVisible(mesh):
                    continue

            c = MFnSingleIndexedComponent(component)
            idxs = MIntArray()
            c.getElements(idxs)

            meshVerts[mesh.partialPathName()] = [
                (w, idx) for idx, w in zip(idxs, mWeights) if w > tolerance
            ]

    return meshVerts
Beispiel #6
0
def setSkinWeights(skinCluster, vertJointWeightData):
    '''
	vertJointWeightData is a list of 2-tuples containing the vertex component name, and a list of 2-tuples
	containing the joint name and weight.  ie it looks like this:
	[ ('someMesh.vtx[0]', [('joint1', 0.25), 'joint2', 0.75)]),
	  ('someMesh.vtx[1]', [('joint1', 0.2), 'joint2', 0.7, 'joint3', 0.1)]),
	  ... ]
	'''

    #convert the vertex component names into vertex indices
    idxJointWeight = []
    for vert, jointsAndWeights in vertJointWeightData:
        idx = int(vert[vert.rindex('[') + 1:-1])
        idxJointWeight.append((idx, jointsAndWeights))

    #get an MObject for the skin cluster node
    skinCluster = apiExtensions.asMObject(skinCluster)
    skinFn = MFnSkinCluster(skinCluster)

    #construct a dict mapping joint names to joint indices
    jApiIndices = {}
    _tmp = MDagPathArray()
    skinFn.influenceObjects(_tmp)
    for n in range(_tmp.length()):
        jApiIndices[str(_tmp[n].node())] = skinFn.indexForInfluenceObject(
            _tmp[n])

    weightListP = skinFn.findPlug("weightList")
    weightListObj = weightListP.attribute()
    weightsP = skinFn.findPlug("weights")

    tmpIntArray = MIntArray()
    baseFmtStr = str(
        skinCluster
    ) + '.weightList[%d]'  #pre build this string: fewer string ops == faster-ness!

    for vertIdx, jointsAndWeights in idxJointWeight:

        #we need to use the api to query the physical indices used
        weightsP.selectAncestorLogicalIndex(vertIdx, weightListObj)
        weightsP.getExistingArrayAttributeIndices(tmpIntArray)

        weightFmtStr = baseFmtStr % vertIdx + '.weights[%d]'

        #clear out any existing skin data - and awesomely we cannot do this with the api - so we need to use a weird ass mel command
        for n in range(tmpIntArray.length()):
            removeMultiInstance(weightFmtStr % tmpIntArray[n])

        #at this point using the api or mel to set the data is a moot point...  we have the strings already so just use mel
        for joint, weight in jointsAndWeights:
            if weight:
                try:
                    infIdx = jApiIndices[joint]
                except KeyError:
                    try:
                        infIdx = jApiIndices[joint.split('|')[0]]
                    except KeyError:
                        continue

                setAttr(weightFmtStr % infIdx, weight)
Beispiel #7
0
def jointVerts( joint, tolerance=1e-4, onlyVisibleMeshes=True ):
	'''
	returns a dict containing data about the verts influences by the given joint - dict keys are mesh names the
	joint affects.  each dict value is a list of tuples containing (weight, idx) for the verts affected by the joint
	'''
	newObjs = []
	meshVerts = {}

	joint = apiExtensions.asMObject( joint )
	jointMDag = joint.dagPath()
	try:
		skins = list( set( listConnections( joint, s=0, type='skinCluster' ) ) )
	except TypeError:
		return meshVerts

	MObject = OpenMaya.MObject
	MDagPath = OpenMaya.MDagPath
	MDoubleArray = OpenMaya.MDoubleArray
	MSelectionList = OpenMaya.MSelectionList
	MIntArray = OpenMaya.MIntArray
	MFnSingleIndexedComponent = OpenMaya.MFnSingleIndexedComponent
	for skin in skins:
		skin = apiExtensions.asMObject( skin )
		mfnSkin = MFnSkinCluster( skin )

		mSel = MSelectionList()
		mWeights = MDoubleArray()
		mfnSkin.getPointsAffectedByInfluence( jointMDag, mSel, mWeights )

		for n in range( mSel.length() ):
			mesh = MDagPath()
			component = MObject()
			mSel.getDagPath( n, mesh, component )

			#if we only want visible meshes - check to see that this mesh is visible
			if onlyVisibleMeshes:
				if not isNodeVisible( mesh ):
					continue

			c = MFnSingleIndexedComponent( component )
			idxs = MIntArray()
			c.getElements( idxs )

			meshVerts[ mesh.partialPathName() ] = [ (w, idx) for idx, w in zip( idxs, mWeights ) if w > tolerance ]

	return meshVerts
Beispiel #8
0
def autoSkinToVolumeMesh( mesh, skeletonMeshRoot ):
	'''
	given a mesh and the root node for a hierarchy mesh volumes, this function will create
	a skeleton with the same hierarchy and skin the mesh to this skeleton using the mesh
	volumes to determine skin weights
	'''

	#grab a list of meshes under the hierarchy - we need to grab this geo, parent it to a skeleton and transfer defacto weighting to the given mesh
	volumes = listRelatives( skeletonMeshRoot, ad=True, type='mesh', pa=True )

	#now generate the skeleton
	transforms = removeDupes( listRelatives( volumes, p=True, type='transform', pa=True ) or [] )
	jointRemap = {}
	for t in transforms:
		select( cl=True )
		jName = '%s_joint' % t
		if objExists( jName ):
			jName += '#'

		j = joint( n=jName )
		jointRemap[ t ] = j

	#now do parenting
	for t, j in jointRemap.iteritems():
		tParent = listRelatives( t, p=True, pa=True )
		if tParent:
			tParent = tParent[0]
			jParent = jointRemap.get( tParent, None )
		else:
			jParent = None

		if jParent is not None:
			parent( j, jParent )

	#now do positioning
	for t in apiExtensions.sortByHierarchy( transforms ):
		j = jointRemap[ t ]
		pos = xform( t, q=True, ws=True, rp=True )
		move( pos[0], pos[1], pos[2], j, ws=True, rpr=True )

	#duplicate the geometry and parent the geo to the joints in the skeleton we just created - store the duplicates so we can delete them later
	dupes = []
	for t, j in jointRemap.iteritems():
		dupe = apiExtensions.asMObject( duplicate( t, returnRootsOnly=True, renameChildren=True )[0] )
		children = listRelatives( dupe, type='transform', pa=True ) or []
		if children:
			delete( children )

		parent( dupe, j )
		dupes.append( dupe )

	f = saveWeights( map( str, dupes ) )

	loadWeights( [mesh], f, usePosition=True, tolerance=0.5, averageVerts=True, jointNameRemapDict=jointRemap )

	delete( dupes )

	return jointRemap
Beispiel #9
0
def replaceGivenConstraintTarget( constraint, targetToReplace, newTarget ):
	'''
	replaces targetToReplace transform on the given constraint with the newTarget transform
	'''
	targetToReplace = apiExtensions.asMObject( targetToReplace )
	newTarget = apiExtensions.asMObject( newTarget )

	#nothing to do if the nodes are the same...
	if apiExtensions.cmpNodes( targetToReplace, newTarget ):
		return

	usedTargetIndices = getAttr( '%s.target' % constraint, multiIndices=True )
	for idx in usedTargetIndices:
		for attr in attributeQuery( 'target', node=constraint, listChildren=True ):
			for connection in listConnections( '%s.target[%s].%s' % (constraint, idx, attr), p=True, type='transform', d=False ) or []:
				toks = connection.split( '.' )
				node = toks[ 0 ]

				if apiExtensions.cmpNodes( node, targetToReplace ):
					toks[ 0 ] = str( newTarget )
					connectAttr( '.'.join( toks ), '%s.target[%s].%s' % (constraint, idx, attr), f=True )
Beispiel #10
0
def replaceConstraintTarget( constraint, newTarget, targetIndex=0 ):
	'''
	replaces the target at "targetIndex" with the new target
	'''
	newTarget = apiExtensions.asMObject( str( newTarget ) )

	for attr in attributeQuery( 'target', node=constraint, listChildren=True ):
		for connection in listConnections( '%s.target[%s].%s' % (constraint, targetIndex, attr), p=True, type='transform', d=False ) or []:
			toks = connection.split( '.' )
			node = toks[ 0 ]

			if not apiExtensions.cmpNodes( node, newTarget ):
				toks[ 0 ] = str( newTarget )
				connectAttr( '.'.join( toks ), '%s.target[%s].%s' % (constraint, targetIndex, attr), f=True )
Beispiel #11
0
def replaceConstraintTarget( constraint, newTarget, targetIndex=0 ):
	'''
	replaces the target at "targetIndex" with the new target
	'''
	newTarget = apiExtensions.asMObject( str( newTarget ) )

	for attr in attributeQuery( 'target', node=constraint, listChildren=True ):
		for connection in listConnections( '%s.target[%s].%s' % (constraint, targetIndex, attr), p=True, type='transform', d=False ) or []:
			toks = connection.split( '.' )
			node = toks[ 0 ]

			if not apiExtensions.cmpNodes( node, newTarget ):
				toks[ 0 ] = str( newTarget )
				connectAttr( '.'.join( toks ), '%s.target[%s].%s' % (constraint, targetIndex, attr), f=True )
def buildControl( name,
                  placementDesc=DEFAULT_PLACE_DESC,
                  pivotModeDesc=PivotModeDesc.MID,
                  shapeDesc=DEFAULT_SHAPE_DESC,
                  colour=DEFAULT_COLOUR,
                  constrain=True,
                  oriented=True,
                  offset=Vector(), offsetSpace=SPACE_OBJECT,
                  size=Vector( (1, 1, 1) ), scale=1.0, autoScale=False,
                  parent=None, qss=None,
                  asJoint=False, freeze=True,
                  lockAttrs=( 'scale', ), hideAttrs=DEFAULT_HIDE_ATTRS,
                  niceName=None ):
	'''
	this rather verbosely called function deals with creating control objects in
	a variety of ways.

	the following args take "struct" like instances of the classes defined above,
	so look to them for more detail on defining those options
	'''

	select( cl=True )

	#sanity checks...
	if not isinstance( placementDesc, PlaceDesc ):
		if isinstance( placementDesc, (list, tuple) ):
			placementDesc = PlaceDesc( *placementDesc )
		else:
			placementDesc = PlaceDesc( placementDesc )

	if not isinstance( shapeDesc, ShapeDesc ):
		if isinstance( shapeDesc, (list, tuple) ):
			shapeDesc = ShapeDesc( *shapeDesc )
		else:
			shapeDesc = ShapeDesc( shapeDesc )

	offset = Vector( offset )


	#unpack placement objects
	place, align, pivot = placementDesc.place, placementDesc.align, placementDesc.pivot

	if shapeDesc.surfaceType == ShapeDesc.SKIN:
		shapeDesc.curveType = ShapeDesc.NULL_SHAPE  #never build curve shapes if the surface type is skin
		if shapeDesc.joints is None:
			shapeDesc.joints = [ str( place ) ]

		shapeDesc.expand *= scale


	#determine auto scale/size - if nessecary
	if autoScale:
		_scale = list( getJointSize( [ place ] + (shapeDesc.joints or []) ) )
		_scale = sorted( _scale )[ -1 ]
		if abs( _scale ) < 1e-2:
			print 'AUTO SCALE FAILED', _scale, name, place
			_scale = scale

		scale = _scale

	if size is AUTO_SIZE:
		tmpKw = {} if oriented else { 'space': SPACE_WORLD }
		size = getJointSize( [ place ] + (shapeDesc.joints or []), **tmpKw )
		for n, v in enumerate( size ):
			if abs( v ) < 1e-2:
				size[ n ] = scale

		scale = 1.0


	#if we're doing a SKIN shape, ensure there is actually geometry skinned to the joints, otherwise bail on the skin and change to the default type
	if shapeDesc.surfaceType == ShapeDesc.SKIN:
		try:
			#loop over all joints and see if there is geo skinned to it
			for j in shapeDesc.joints:
				verts = meshUtils.jointVerts( j, tolerance=DEFAULT_SKIN_EXTRACTION_TOLERANCE )

				#if so throw a breakException to bail out of the loop
				if verts: raise BreakException

			#if we get this far that means none of the joints have geo skinned to them - so set the surface and curve types to their default values
			shapeDesc.surfaceType = shapeDesc.curveType = ShapeDesc.DEFAULT_TYPE
			print 'WARNING - surface type was set to SKIN, but no geometry is skinned to the joints: %s' % shapeDesc.joints
		except BreakException: pass


	#build the curve shapes first
	if shapeDesc.curveType != ShapeDesc.NULL_SHAPE \
	   and shapeDesc.curveType != ShapeDesc.SKIN:
		curveShapeFile = getFileForShapeName( shapeDesc.curveType )
		assert curveShapeFile is not None, "cannot find shape %s" % shapeDesc.curveType

		createCmd = ''.join( curveShapeFile.read() )
		mel.eval( createCmd )
	else:
		select( group( em=True ) )

	sel = ls( sl=True )
	obj = asMObject( sel[ 0 ] )

	#now to deal with the surface - if its different from the curve, then build it
	if shapeDesc.surfaceType != shapeDesc.curveType \
	   and shapeDesc.surfaceType != ShapeDesc.NULL_SHAPE \
	   and shapeDesc.surfaceType != ShapeDesc.SKIN:

		#if the typesurface is different from the typecurve, then first delete all existing surface shapes under the control
		shapesTemp = listRelatives( obj, s=True, pa=True )
		for s in shapesTemp:
			if nodeType( s ) == "nurbsSurface":
				delete( s )

		#now build the temporary control
		surfaceShapeFile = getFileForShapeName( shapeDesc.surfaceType )
		assert surfaceShapeFile is not None, "cannot find shape %s" % shapeDesc.surfaceType

		createCmd = ''.join( surfaceShapeFile.read() )
		mel.eval( createCmd )

		#and parent its surface shape nodes to the actual control, and then delete it
		tempSel = ls( sl=True )
		shapesTemp = listRelatives( tempSel[0], s=True, pa=True ) or []
		for s in shapesTemp:
			if nodeType(s) == "nurbsSurface":
				cmd.parent( s, obj, add=True, s=True )

		delete( tempSel[ 0 ] )
		select( sel )


	#if the joint flag is true, parent the object shapes under a joint instead of a transform node
	if asJoint:
		select( cl=True )
		j = joint()
		for s in listRelatives( obj, s=True, pa=True ) or []:
			cmd.parent( s, j, add=True, s=True )

		setAttr( '%s.radius' % j, keyable=False )
		delete( obj )
		obj = asMObject( j )

	setAttr( '%s.s' % obj, scale, scale, scale )


	#rename the object
	if not name: name = 'control'
	rename( obj, name )


	#move the pivot - if needed
	makeIdentity( obj, a=1, s=1 )
	shapeStrs = getShapeStrs( obj )
	if pivotModeDesc == PivotModeDesc.TOP:
		for s in shapeStrs:
			move(  0, -scale/2.0, 0, s, r=True )
	elif pivotModeDesc == PivotModeDesc.BASE:
		for s in shapeStrs:
			move(  0, scale/2.0, 0, s, r=True )


	#rotate it accordingly
	rot = AXIS_ROTATIONS[ shapeDesc.axis ]
	rotate( rot[0], rot[1], rot[2], obj, os=True )
	makeIdentity( obj, a=1, r=1 )


	#if the user wants the control oriented, create the orientation group and parent the control
	grp = obj
	if oriented:
		grp = group( em=True, n="%s_space#" % obj )
		cmd.parent( obj, grp )
		attrState( grp, ['s', 'v'], *LOCK_HIDE )
		if align is not None:
			delete( parentConstraint( align, grp ) )


	#place and align
	if place:
		delete( pointConstraint( place, grp ) )

	if align:
		delete( orientConstraint( align, grp ) )
	else:
		rotate( 0, 0, 0, grp, a=True, ws=True )


	#do the size scaling...
	if shapeDesc.surfaceType != ShapeDesc.SKIN:
		for s in getShapeStrs( obj ):
			cmd.scale( size[0], size[1], size[2], s )


	#if the parent exists - parent the new control to the given parent
	if parent is not None:
		grp = cmd.parent( grp, parent )[0]


	#do offset
	for s in getShapeStrs( obj ):
		mkw = { 'r': True }
		if offsetSpace == SPACE_OBJECT: mkw[ 'os' ] = True
		elif offsetSpace == SPACE_LOCAL: mkw[ 'ls' ] = True
		elif offsetSpace == SPACE_WORLD: mkw[ 'ws' ] = True
		if offset:
			move( offset[0], offset[1], offset[2], s, **mkw )

	if freeze:
		makeIdentity( obj, a=1, r=1 )

	makeIdentity( obj, a=1, t=1 )  #always freeze translations


	#delete shape data that we don't want
	if shapeDesc.curveType is None:
		for s in listRelatives( obj, s=True, pa=True ) or []:
			if nodeType(s) == "nurbsCurve":
				delete(s)

	if shapeDesc.surfaceType is None:
		for s in listRelatives( obj, s=True, pa=True ) or []:
			if nodeType(s) == "nurbsSurface":
				delete(s)


	#now snap the pivot to alignpivot object if it exists
	if pivot is not None and objExists( pivot ):
		p = placementDesc.pivotPos
		move( p[0], p[1], p[2], '%s.rp' % obj, '%s.sp' % obj, a=True, ws=True, rpr=True )


	#constrain the target object to this control?
	if constrain:
		#check to see if the transform is constrained already - if so, bail.  buildControl doesn't do multi constraints
		if not listConnections( pivot, d=0, type='constraint' ):
			if place:
				parentConstraint( obj, pivot, mo=True )
				setItemRigControl( pivot, obj )


	#if the user has specified skin geometry as the representation type, then build the geo
	#NOTE: this really needs to happen after ALL the placement has happened otherwise the extracted
	#will be offset from the surface its supposed to be representing
	if shapeDesc.surfaceType == ShapeDesc.SKIN:

		#extract the surface geometry
		geo = meshUtils.extractMeshForJoints( shapeDesc.joints, expand=shapeDesc.expand )

		#if the geo is None, use the default control representation instead
		writeTrigger = True
		if geo is None:
			writeTrigger = False
			curveShapeFile = getFileForShapeName( ShapeDesc.DEFAULT_TYPE )
			createCmd = ''.join( curveShapeFile.read() )
			mel.eval( createCmd )
			geo = ls( sl=True )[ 0 ]

		geo = cmd.parent( geo, obj )[0]
		makeIdentity( geo, a=True, s=True, r=True, t=True )

		cmd.parent( listRelatives( geo, s=True, pa=True ), obj, add=True, s=True )
		delete( geo )

		#when selected, turn the mesh display off, and only highlight edges
		if writeTrigger:
			triggered.Trigger.CreateTrigger( str( obj ), cmdStr="for( $s in `listRelatives -s -pa #` ) setAttr ( $s +\".displayEdges\" ) 2;" )


	#build a shader for the control
	if colour is not None:
		colours.setObjShader( obj, colours.getShader( colour, True ) )


	#add to a selection set if desired
	if qss is not None:
		sets( obj, add=qss )


	#hide and lock attributes
	attrState( obj, lockAttrs, lock=True )
	attrState( obj, hideAttrs, show=False )

	if niceName:
		setNiceName( obj, niceName )


	return obj
Beispiel #13
0
def setupBaseLimbTwister( joint, aimObject, upObject, aimAxis ):
	'''
	Builds a bicep twist rig.

	Bicep twist joints are basically joints that sit next to the bicep (humerous) in the hierarchy and take
	all the weighting of the deltoid and upper triceps.  Bicep twists don't rotate on their twist axis, but
	aim at the elbow, so they basically do exactly as the humerous does but don't twist.
	'''
	if not isinstance( aimAxis, Axis ):
		aimAxis = Axis.FromName( aimAxis )

	upAxes = [ ax.asVector() for ax in aimAxis.otherAxes() ]

	joint = apiExtensions.asMObject( joint )
	upObject = apiExtensions.asMObject( upObject )

	jWorldMatrix = joint.getWorldMatrix()
	upVectorsWorld = [ ax * jWorldMatrix for ax in upAxes ]

	upWorldInvMatrix = upObject.getWorldInverseMatrix()

	#we want to transform the aimObject's two different axes into the space of the up object
	upVectorsLocal = [ upVectorsWorld[0] * upWorldInvMatrix,
	                   upVectorsWorld[1] * upWorldInvMatrix ]

	matrixMult = createNode( 'pointMatrixMult', n='bicepTwister_primaryUpAxis' )
	setAttr( '%s.inPoint' % matrixMult, *upVectorsLocal[0] )
	setAttr( '%s.vectorMultiply' % matrixMult, True )
	connectAttr( '%s.worldMatrix[0]' % upObject, '%s.inMatrix' % matrixMult )

	vectorProduct = createNode( 'vectorProduct' )
	connectAttr( '%s.output' % matrixMult, '%s.input1' % vectorProduct )
	setAttr( '%s.operation' % vectorProduct, 1 )

	aimNode = aimConstraint( aimObject, joint, aim=aimAxis.asVector(), wuo=upObject, wut='objectrotation' )[0]
	addAttr( aimNode, ln='upAndAimDot', at='double' )

	#create an expression to normalize the constraintVector attribute coming out of the aimConstraint node - its not normalized, and the vector product node doesn't normalize inputs (wtf?!)
	expressionStr = '''float $mag = sqrt( (%(aimNode)s.constraintVectorX * %(aimNode)s.constraintVectorX) + (%(aimNode)s.constraintVectorY * %(aimNode)s.constraintVectorY) + (%(aimNode)s.constraintVectorZ * %(aimNode)s.constraintVectorZ) ) + 1;
float $normX = %(aimNode)s.constraintVectorX / $mag;
float $normY = %(aimNode)s.constraintVectorY / $mag;
float $normZ = %(aimNode)s.constraintVectorZ / $mag;
%(vectorProduct)s.input2X = %(matrixMult)s.outputX * $normX;
%(vectorProduct)s.input2Y = %(matrixMult)s.outputX * $normY;
%(vectorProduct)s.input2Z = %(matrixMult)s.outputX * $normZ;''' % locals()

	expression( s=expressionStr )

	sdkDriver = '%s.outputX' % vectorProduct
	connectAttr( sdkDriver, '%s.upAndAimDot' % aimNode )

	for upAxis, upVector, driverValues in zip( upAxes, upVectorsLocal, ((0, 0.1), (0.9, 1)) ):
		for driverValue in driverValues:
			for upAxisValue, upVectorValue, axisName in zip( upAxis, upVector, Axis.BASE_AXES ):
				axisName = axisName.upper()
				setDrivenKeyframe( '%s.upVector%s' % (aimNode, axisName), value=upAxisValue,
					               currentDriver=sdkDriver, driverValue=driverValue, itt='linear', ott='linear' )

				setDrivenKeyframe( '%s.worldUpVector%s' % (aimNode, axisName), value=upVectorValue,
					               currentDriver=sdkDriver, driverValue=driverValue, itt='linear', ott='linear' )

	for axisName in Axis.BASE_AXES:
		axisName = axisName.upper()
		setInfinity( '%s.upVector%s' % (aimNode, axisName), pri='oscillate', poi='oscillate' )
		setInfinity( '%s.worldUpVector%s' % (aimNode, axisName), pri='oscillate', poi='oscillate' )
Beispiel #14
0
def buildControl(name,
                 placementDesc=DEFAULT_PLACE_DESC,
                 pivotModeDesc=PivotModeDesc.MID,
                 shapeDesc=DEFAULT_SHAPE_DESC,
                 colour=DEFAULT_COLOUR,
                 constrain=True,
                 oriented=True,
                 offset=Vector((0, 0, 0)),
                 offsetSpace=SPACE_OBJECT,
                 size=Vector((1, 1, 1)),
                 scale=1.0,
                 autoScale=False,
                 parent=None,
                 qss=None,
                 asJoint=False,
                 freeze=True,
                 lockAttrs=('scale', ),
                 hideAttrs=DEFAULT_HIDE_ATTRS,
                 niceName=None,
                 displayLayer=None):
    '''
	this rather verbosely called function deals with creating control objects in
	a variety of ways.

	the following args take "struct" like instances of the classes defined above,
	so look to them for more detail on defining those options

	displayLayer (int) will create layers (if doesn't exist) and add control shape to that layer.
	layer None or zero doesn't create.
	'''

    select(cl=True)

    #sanity checks...
    if not isinstance(placementDesc, PlaceDesc):
        if isinstance(placementDesc, (list, tuple)):
            placementDesc = PlaceDesc(*placementDesc)
        else:
            placementDesc = PlaceDesc(placementDesc)

    if not isinstance(shapeDesc, ShapeDesc):
        if isinstance(shapeDesc, (list, tuple)):
            shapeDesc = ShapeDesc(*shapeDesc)
        else:
            shapeDesc = ShapeDesc(shapeDesc)

    offset = Vector(offset)

    #if we've been given a parent, cast it to be an MObject so that if its name path changes (for example if
    #parent='aNode' and we create a control called 'aNode' then the parent's name path will change to '|aNode' - yay!)
    if parent:
        parent = asMObject(parent)

    #unpack placement objects
    place, align, pivot = placementDesc.place, placementDesc.align, placementDesc.pivot

    if shapeDesc.surfaceType == ShapeDesc.SKIN:
        shapeDesc.curveType = ShapeDesc.NULL_SHAPE  #never build curve shapes if the surface type is skin
        if shapeDesc.joints is None:
            shapeDesc.joints = [str(place)]

        shapeDesc.expand *= scale

    #determine auto scale/size - if nessecary
    if autoScale:
        _scale = list(getJointSize([place] + (shapeDesc.joints or [])))
        _scale = sorted(_scale)[-1]
        if abs(_scale) < 1e-2:
            print 'AUTO SCALE FAILED', _scale, name, place
            _scale = scale

        scale = _scale

    if size is AUTO_SIZE:
        tmpKw = {} if oriented else {'space': SPACE_WORLD}
        size = getJointSize([place] + (shapeDesc.joints or []), **tmpKw)
        for n, v in enumerate(size):
            if abs(v) < 1e-2:
                size[n] = scale

        scale = 1.0

    #if we're doing a SKIN shape, ensure there is actually geometry skinned to the joints, otherwise bail on the skin and change to the default type
    if shapeDesc.surfaceType == ShapeDesc.SKIN:
        try:
            #loop over all joints and see if there is geo skinned to it
            for j in shapeDesc.joints:
                verts = meshUtils.jointVerts(
                    j, tolerance=DEFAULT_SKIN_EXTRACTION_TOLERANCE)

                #if so throw a breakException to bail out of the loop
                if verts:
                    raise BreakException

            #if we get this far that means none of the joints have geo skinned to them - so set the surface and curve types to their default values
            shapeDesc.surfaceType = shapeDesc.curveType = ShapeDesc.DEFAULT_TYPE
            print 'WARNING - surface type was set to SKIN, but no geometry is skinned to the joints: %s' % shapeDesc.joints
        except BreakException:
            pass

    #build the curve shapes first
    if shapeDesc.curveType != ShapeDesc.NULL_SHAPE \
       and shapeDesc.curveType != ShapeDesc.SKIN:
        curveShapeFile = getFileForShapeName(shapeDesc.curveType)
        assert curveShapeFile is not None, "cannot find shape %s" % shapeDesc.curveType

        createCmd = ''.join(curveShapeFile.read())
        mel.eval(createCmd)
    else:
        select(group(em=True))

    sel = ls(sl=True)
    obj = asMObject(sel[0])

    #now to deal with the surface - if its different from the curve, then build it
    if shapeDesc.surfaceType != shapeDesc.curveType \
       and shapeDesc.surfaceType != ShapeDesc.NULL_SHAPE \
       and shapeDesc.surfaceType != ShapeDesc.SKIN:

        #if the typesurface is different from the typecurve, then first delete all existing surface shapes under the control
        shapesTemp = listRelatives(obj, s=True, pa=True)
        for s in shapesTemp:
            if nodeType(s) == "nurbsSurface":
                delete(s)

        #now build the temporary control
        surfaceShapeFile = getFileForShapeName(shapeDesc.surfaceType)
        assert surfaceShapeFile is not None, "cannot find shape %s" % shapeDesc.surfaceType

        createCmd = ''.join(surfaceShapeFile.read())
        mel.eval(createCmd)

        #and parent its surface shape nodes to the actual control, and then delete it
        tempSel = ls(sl=True)
        shapesTemp = listRelatives(tempSel[0], s=True, pa=True) or []
        for s in shapesTemp:
            if nodeType(s) == "nurbsSurface":
                cmd.parent(s, obj, add=True, s=True)

        delete(tempSel[0])
        select(sel)

    #if the joint flag is true, parent the object shapes under a joint instead of a transform node
    if asJoint:
        select(cl=True)
        j = joint()
        for s in listRelatives(obj, s=True, pa=True) or []:
            cmd.parent(s, j, add=True, s=True)

        setAttr('%s.radius' % j, keyable=False)
        setAttr('%s.radius' % j, cb=False)
        delete(obj)
        obj = asMObject(j)

    setAttr('%s.s' % obj, scale, scale, scale)

    #rename the object - if no name has been given, call it "control".  if there is a node with the name already, get maya to uniquify it
    if not name:
        name = 'control'

    if objExists(name):
        name = '%s#' % name

    rename(obj, name)

    #move the pivot - if needed
    makeIdentity(obj, a=1, s=1)
    shapeStrs = getShapeStrs(obj)
    if pivotModeDesc == PivotModeDesc.TOP:
        for s in shapeStrs:
            move(0, -scale / 2.0, 0, s, r=True)
    elif pivotModeDesc == PivotModeDesc.BASE:
        for s in shapeStrs:
            move(0, scale / 2.0, 0, s, r=True)

    #rotate it accordingly
    rot = AXIS_ROTATIONS[shapeDesc.axis]
    rotate(rot[0], rot[1], rot[2], obj, os=True)
    makeIdentity(obj, a=1, r=1)

    #if the user wants the control oriented, create the orientation group and parent the control
    grp = obj
    if oriented:
        grp = group(em=True, n="%s_space#" % obj)
        cmd.parent(obj, grp)
        attrState(grp, ['s', 'v'], *LOCK_HIDE)
        if align is not None:
            delete(parentConstraint(align, grp))

    #place and align
    if place:
        delete(pointConstraint(place, grp))

    if align:
        delete(orientConstraint(align, grp))
    else:
        rotate(0, 0, 0, grp, a=True, ws=True)

    #do the size scaling...
    if shapeDesc.surfaceType != ShapeDesc.SKIN:
        for s in getShapeStrs(obj):
            cmd.scale(size[0], size[1], size[2], s)

    #if the parent exists - parent the new control to the given parent
    if parent is not None:
        grp = cmd.parent(grp, parent)[0]

    #do offset
    for s in getShapeStrs(obj):
        mkw = {'r': True}
        if offsetSpace == SPACE_OBJECT: mkw['os'] = True
        elif offsetSpace == SPACE_LOCAL: mkw['ls'] = True
        elif offsetSpace == SPACE_WORLD: mkw['ws'] = True
        if offset:
            move(offset[0], offset[1], offset[2], s, **mkw)

    if freeze:
        makeIdentity(obj, a=1, r=1)

    makeIdentity(obj, a=1, t=1)  #always freeze translations

    #delete shape data that we don't want
    if shapeDesc.curveType is None:
        for s in listRelatives(obj, s=True, pa=True) or []:
            if nodeType(s) == "nurbsCurve":
                delete(s)

    if shapeDesc.surfaceType is None:
        for s in listRelatives(obj, s=True, pa=True) or []:
            if nodeType(s) == "nurbsSurface":
                delete(s)

    #now snap the pivot to alignpivot object if it exists
    if pivot is not None and objExists(pivot):
        p = placementDesc.pivotPos
        move(p[0],
             p[1],
             p[2],
             '%s.rp' % obj,
             '%s.sp' % obj,
             a=True,
             ws=True,
             rpr=True)

    #constrain the target object to this control?
    if constrain:
        #check to see if the transform is constrained already - if so, bail.  buildControl doesn't do multi constraints
        if not listConnections(pivot, d=0, type='constraint'):
            if place:
                parentConstraint(obj, pivot, mo=True)
                setItemRigControl(pivot, obj)

    #if the user has specified skin geometry as the representation type, then build the geo
    #NOTE: this really needs to happen after ALL the placement has happened otherwise the extracted
    #will be offset from the surface its supposed to be representing
    if shapeDesc.surfaceType == ShapeDesc.SKIN:

        #extract the surface geometry
        geo = meshUtils.extractMeshForJoints(shapeDesc.joints,
                                             expand=shapeDesc.expand)

        #if the geo is None, use the default control representation instead
        writeTrigger = True
        if geo is None:
            writeTrigger = False
            curveShapeFile = getFileForShapeName(ShapeDesc.DEFAULT_TYPE)
            createCmd = ''.join(curveShapeFile.read())
            mel.eval(createCmd)
            geo = ls(sl=True)[0]

        geo = cmd.parent(geo, obj)[0]
        makeIdentity(geo, a=True, s=True, r=True, t=True)

        cmd.parent(listRelatives(geo, s=True, pa=True), obj, add=True, s=True)
        delete(geo)

        #when selected, turn the mesh display off, and only highlight edges
        if writeTrigger:
            triggered.Trigger.CreateTrigger(
                str(obj),
                cmdStr=
                "for( $s in `listRelatives -s -pa #` ) setAttr ( $s +\".displayEdges\" ) 2;"
            )

    #build a shader for the control
    if colour is not None:
        colours.setObjShader(obj, colours.getShader(colour, True))

    #add to a selection set if desired
    if qss is not None:
        sets(obj, add=qss)

    #hide and lock attributes
    attrState(obj, lockAttrs, lock=True)
    attrState(obj, hideAttrs, show=False)

    if niceName:
        setNiceName(obj, niceName)

    # display layer
    if displayLayer and not int(displayLayer) <= 0:
        layerName = 'ctrl_%d' % int(displayLayer)
        allLayers = ls(type='displayLayer')

        layer = ''
        if layerName in allLayers:
            layer = layerName
        else:
            layer = createDisplayLayer(n=layerName, number=1, empty=True)
            setAttr('%s.color' % layer, 24 + int(displayLayer))

        for s in listRelatives(obj, s=True, pa=True) or []:
            connectAttr('%s.drawInfo.visibility' % layer, '%s.v' % s)
            connectAttr('%s.drawInfo.displayType' % layer,
                        '%s.overrideDisplayType' % s)

    return obj
def loadPresetFile(presetFilepath):
    """
	deals with unserializing a skeleton preset definition into the scene
	"""

    assert presetFilepath.exists, "No preset file found!  %" % presetFilepath
    itemRemapDict = {}
    partList = []

    def cleanUp():
        # removes all items built should an exception occur
        for partType, partItems in partList:
            if partItems:
                delete(partItems[0])

    lines = presetFilepath.read()
    linesIter = iter(lines)
    version = linesIter.next().strip()

    try:
        for line in linesIter:
            line = line.strip()

            # blank line?  skip...
            if not line:
                continue

            if line == "<part>":
                partTypeAndBuildKwargLine = linesIter.next().strip()
                toks = partTypeAndBuildKwargLine.split("=")
                numToks = len(toks)
                if numToks == 1:
                    partType, partBuildKwargs = toks[0], {}
                elif numToks == 2:
                    partType, partBuildKwargs = toks
                    partBuildKwargs = eval(partBuildKwargs)

                partItems = []

                partList.append((partType, partBuildKwargs, partItems))

                while True:
                    line = linesIter.next().strip()

                    # blank line?  skip...
                    if not line:
                        continue

                        # are we done with the part?
                    if line == "</part>":
                        break

                    itemAndParent, attrInfo = line.split("=")
                    item, parent = itemAndParent.split(",")
                    attrBlocks = attrInfo.split(";")

                    # construct the attr dict
                    attrDict = {}
                    for block in attrBlocks:
                        if not block:
                            continue

                        attrName, attrData = block.split(":")
                        attrData = [d for d in attrData.split(",") if d]
                        attrDict[attrName] = attrData

                        # build the actual joint
                    actualItem = apiExtensions.asMObject(createNode("joint", n=item))

                    # insert the item and what it actually maps to in the scene into the itemRemapDict
                    itemRemapDict[item] = actualItem

                    # finally append to the list of items in this part
                    partItems.append((actualItem, parent, attrDict))
    except StopIteration:
        cleanUp()
        raise IOError("File is incomplete!")
    except:
        cleanUp()
        raise

    parts = []
    for partType, partBuildKwargs, partItems in partList:
        items = []
        for (actualItem, parent, attrDict) in partItems:
            actualParent = itemRemapDict.get(parent, None)

            # do parenting if appropriate
            if actualParent is not None:
                cmd.parent(actualItem, actualParent)

                # set the joint size
            if "radius" in attrDict:
                size = attrDict["radius"][0]
                setAttr("%s.radius" % actualItem, float(size))

                # move to the appropriate position
            if "t" in attrDict:
                tx, ty, tz = map(float, attrDict["t"])
                move(tx, ty, tz, actualItem, a=True, ws=True, rpr=True)

                # rotate appropriately
            if "r" in attrDict:
                rx, ry, rz = map(float, attrDict["r"])
                rotate(rx, ry, rz, actualItem, a=True, ws=True)

                # append to the items list - so we can instantiate the part once we've finished building the items
            items.append(actualItem)

            # instantiate the part and append it to the list of parts created
        partClass = SkeletonPart.GetNamedSubclass(partType)
        part = partClass([str(i) for i in items])
        part.convert(partBuildKwargs)

        parts.append(part)

    setupAutoMirror()
    for part in SkeletonPart.IterAllParts():
        part.visualize()

    return parts
Beispiel #16
0
def setupBaseLimbTwister(joint, aimObject, upObject, aimAxis):
    '''
	Builds a bicep twist rig.

	Bicep twist joints are basically joints that sit next to the bicep (humerous) in the hierarchy and take
	all the weighting of the deltoid and upper triceps.  Bicep twists don't rotate on their twist axis, but
	aim at the elbow, so they basically do exactly as the humerous does but don't twist.
	'''
    if not isinstance(aimAxis, Axis):
        aimAxis = Axis.FromName(aimAxis)

    upAxes = [ax.asVector() for ax in aimAxis.otherAxes()]

    joint = apiExtensions.asMObject(joint)
    upObject = apiExtensions.asMObject(upObject)

    jWorldMatrix = joint.getWorldMatrix()
    upVectorsWorld = [ax * jWorldMatrix for ax in upAxes]

    upWorldInvMatrix = upObject.getWorldInverseMatrix()

    #we want to transform the aimObject's two different axes into the space of the up object
    upVectorsLocal = [
        upVectorsWorld[0] * upWorldInvMatrix,
        upVectorsWorld[1] * upWorldInvMatrix
    ]

    matrixMult = createNode('pointMatrixMult', n='bicepTwister_primaryUpAxis')
    setAttr('%s.inPoint' % matrixMult, *upVectorsLocal[0])
    setAttr('%s.vectorMultiply' % matrixMult, True)
    connectAttr('%s.worldMatrix[0]' % upObject, '%s.inMatrix' % matrixMult)

    vectorProduct = createNode('vectorProduct')
    connectAttr('%s.output' % matrixMult, '%s.input1' % vectorProduct)
    setAttr('%s.operation' % vectorProduct, 1)

    aimNode = aimConstraint(aimObject,
                            joint,
                            aim=aimAxis.asVector(),
                            wuo=upObject,
                            wut='objectrotation')[0]
    addAttr(aimNode, ln='upAndAimDot', at='double')

    #create an expression to normalize the constraintVector attribute coming out of the aimConstraint node - its not normalized, and the vector product node doesn't normalize inputs (wtf?!)
    expressionStr = '''float $mag = sqrt( (%(aimNode)s.constraintVectorX * %(aimNode)s.constraintVectorX) + (%(aimNode)s.constraintVectorY * %(aimNode)s.constraintVectorY) + (%(aimNode)s.constraintVectorZ * %(aimNode)s.constraintVectorZ) ) + 1;
float $normX = %(aimNode)s.constraintVectorX / $mag;
float $normY = %(aimNode)s.constraintVectorY / $mag;
float $normZ = %(aimNode)s.constraintVectorZ / $mag;
%(vectorProduct)s.input2X = %(matrixMult)s.outputX * $normX;
%(vectorProduct)s.input2Y = %(matrixMult)s.outputX * $normY;
%(vectorProduct)s.input2Z = %(matrixMult)s.outputX * $normZ;''' % locals()

    expression(s=expressionStr)

    sdkDriver = '%s.outputX' % vectorProduct
    connectAttr(sdkDriver, '%s.upAndAimDot' % aimNode)

    for upAxis, upVector, driverValues in zip(upAxes, upVectorsLocal,
                                              ((0, 0.1), (0.9, 1))):
        for driverValue in driverValues:
            for upAxisValue, upVectorValue, axisName in zip(
                    upAxis, upVector, Axis.BASE_AXES):
                axisName = axisName.upper()
                setDrivenKeyframe('%s.upVector%s' % (aimNode, axisName),
                                  value=upAxisValue,
                                  currentDriver=sdkDriver,
                                  driverValue=driverValue,
                                  itt='linear',
                                  ott='linear')

                setDrivenKeyframe('%s.worldUpVector%s' % (aimNode, axisName),
                                  value=upVectorValue,
                                  currentDriver=sdkDriver,
                                  driverValue=driverValue,
                                  itt='linear',
                                  ott='linear')

    for axisName in Axis.BASE_AXES:
        axisName = axisName.upper()
        setInfinity('%s.upVector%s' % (aimNode, axisName),
                    pri='oscillate',
                    poi='oscillate')
        setInfinity('%s.worldUpVector%s' % (aimNode, axisName),
                    pri='oscillate',
                    poi='oscillate')
	def __hash__( self ):
		'''
		the hash for the container mobject uniquely identifies this rig control
		'''
		return hash( apiExtensions.asMObject( self.container ) )
Beispiel #18
0
def loadPresetFile(presetFilepath):
    '''
	deals with unserializing a skeleton preset definition into the scene
	'''

    assert presetFilepath.exists(), "No preset file found!  %" % presetFilepath
    itemRemapDict = {}
    partList = []

    def cleanUp():
        #removes all items built should an exception occur
        for partType, partItems in partList:
            if partItems:
                delete(partItems[0])

    lines = presetFilepath.read()
    linesIter = iter(lines)
    version = linesIter.next().strip()

    try:
        for line in linesIter:
            line = line.strip()

            #blank line?  skip...
            if not line:
                continue

            if line == '<part>':
                partTypeAndBuildKwargLine = linesIter.next().strip()
                toks = partTypeAndBuildKwargLine.split('=')
                numToks = len(toks)
                if numToks == 1:
                    partType, partBuildKwargs = toks[0], {}
                elif numToks == 2:
                    partType, partBuildKwargs = toks
                    partBuildKwargs = eval(partBuildKwargs)

                partItems = []

                partList.append((partType, partBuildKwargs, partItems))

                while True:
                    line = linesIter.next().strip()

                    #blank line?  skip...
                    if not line:
                        continue

                    #are we done with the part?
                    if line == '</part>':
                        break

                    itemAndParent, attrInfo = line.split('=')
                    item, parent = itemAndParent.split(',')
                    attrBlocks = attrInfo.split(';')

                    #construct the attr dict
                    attrDict = {}
                    for block in attrBlocks:
                        if not block:
                            continue

                        attrName, attrData = block.split(':')
                        attrData = [d for d in attrData.split(',') if d]
                        attrDict[attrName] = attrData

                    #build the actual joint
                    actualItem = apiExtensions.asMObject(
                        createNode('joint', n=item))

                    #insert the item and what it actually maps to in the scene into the itemRemapDict
                    itemRemapDict[item] = actualItem

                    #finally append to the list of items in this part
                    partItems.append((actualItem, parent, attrDict))
    except StopIteration:
        cleanUp()
        raise IOError("File is incomplete!")
    except:
        cleanUp()
        raise

    parts = []
    for partType, partBuildKwargs, partItems in partList:
        items = []
        for (actualItem, parent, attrDict) in partItems:
            actualParent = itemRemapDict.get(parent, None)

            #do parenting if appropriate
            if actualParent is not None:
                cmd.parent(actualItem, actualParent)

            #set the joint size
            if 'radius' in attrDict:
                size = attrDict['radius'][0]
                setAttr('%s.radius' % actualItem, float(size))

            #move to the appropriate position
            if 't' in attrDict:
                tx, ty, tz = map(float, attrDict['t'])
                move(tx, ty, tz, actualItem, a=True, ws=True, rpr=True)

            #rotate appropriately
            if 'r' in attrDict:
                rx, ry, rz = map(float, attrDict['r'])
                rotate(rx, ry, rz, actualItem, a=True, ws=True)

            #append to the items list - so we can instantiate the part once we've finished building the items
            items.append(actualItem)

        #instantiate the part and append it to the list of parts created
        partClass = SkeletonPart.GetNamedSubclass(partType)
        partContainer = buildSkeletonPartContainer(partClass, partBuildKwargs,
                                                   items)
        part = partClass(partContainer)
        part.convert(partBuildKwargs)

        parts.append(part)

    setupAutoMirror()
    for part in SkeletonPart.IterAllParts():
        part.visualize()

    return parts