def get_slow(mesh): ''' Given a mesh, returns a list, one entry per vertex, with a list of (joint, value) pairs. ex: [0] = [ (ja, .5), (jb, .5) ] [1] = [ (ja, .5), (jb, .25), (jc, .25) ] ''' skinClusterName = mel.findRelatedSkinCluster(mesh) joints = cmds.skinCluster(mesh.name(), q=True, inf=True) weights = [] required = {} for j in joints: parent = cmds.listRelatives(j, p=True) required[j] = [parent[0] if parent else None] + cmds.xform(j, q=True, ws=True, t=True) info = { 'joints': required, 'weights': weights, } vtxStr = mesh.name() + '.vtx[%i]' for i in xrange(mesh.vtx.count()): weights.append( [(t, v) for t, v in zip(joints, cmds.skinPercent(skinClusterName, vtxStr % i, q=1, v=1)) if v > 0] ) return info
def getShapeInfo_DEPRECATED(name, controller): ''' Returns a list of strings representing the shape of the given controller ''' extraInfo = {'color': getShader(controller)} for shape in core.shape.getShapes(controller): extraInfo['curveColor'] = shape.overrideColor.get() if controller.hasAttr('shapeType'): extraInfo['shapeType'] = controller.shapeType.get() lines = [name + ':' + json.dumps(extraInfo)] for shape in core.shape.getShapes(controller): # pos = [xform(cv, q=True, os=True, t=True) for cv in shape.cv] # Iterating cvs in mel is 2-6x faster if shape.type() == 'nurbsCurve': cvStr = shape.name() + '.cv[%i]' localPos = [ cmds.xform(cvStr % i, q=True, os=True, t=True) for i in xrange(shape.numCVs()) ] worldPos = [ cmds.xform(cvStr % i, q=True, ws=True, t=True) for i in xrange(shape.numCVs()) ] else: cvStr = shape.name() + '.cv[%i][%i]' localPos = [ cmds.xform(cvStr % (u, v), q=True, os=True, t=True) for u in xrange(shape.numCVsInU()) for v in xrange(shape.numCVsInV()) ] worldPos = [ cmds.xform(cvStr % (u, v), q=True, ws=True, t=True) for u in xrange(shape.numCVsInU()) for v in xrange(shape.numCVsInV()) ] lines.append(' ' + shape.type() + '|os ' + str(localPos)) lines.append(' ' + shape.type() + '|ws ' + str(worldPos)) return lines
def skeletonToJson(root): skel = {} for j in [root] + root.listRelatives(ad=True, type='joint'): parentName = j.getParent().shortName() skel[ j.shortName() ] = { 'parent': parentName, 'pos': cmds.xform(j.name(), q=True, ws=True, t=True), 'jo': list(j.jointOrient.get()) } return skel
def orientJoint(jnt, target, upTarget=None, aim='x', up='y', upVector=None): ''' Orient an object (doesn't have to be a joint) to the target. Basically a code only aiming. :param PyNode jnt: The joint to orient :param PyNode target: The object to orient to. :param PyNode/upTarget pos: A PyNode or position [x,y,z] for the up vector :param upVector: If specified, upTarget is not needed :param chr aim: This works for aim=x, up=y and negative versions Things to investigate: * Sometimes the rotations are different but that turns out to be -0.0 in the matrix. AFAIK, everything still ends up fine. # Adept ends up with the same JOs! # Minotaur is the same * It looks like rotate order doesn't matter It's (almost) an all code version of: if isinstance(pos, PyNode): upObj = pos else: upObj = spaceLocator() upObj.t.set( pos ) aim = axisConvert(aim) up = axisConvert(up) # Temporarily unparent children and clear orientation. with lib.core.dagObj.Solo( jnt ): jnt.r.set(0, 0, 0) jnt.jo.set(0, 0, 0) const = aimConstraint( target, jnt, aim=aim, u=up, wut='object', wuo=upObj ) jnt.jo.set( jnt.r.get() ) delete( const ) jnt.r.set(0, 0, 0) def axisConvert( axisChar ): """ Turn a character representing an axis into 3 numbers, ex x = [1,0,0], -y = [0,-1,0] :param char axisChar: Either "x", "y" or "z", possibly negated, eg: "-x" """ axis = [0, 0, 0] c = axisChar[-1] axis[ ord(c) - ord('x') ] = -1 if axisChar.startswith('-') else 1 return axis ''' #print jnt, target, pos, aim, up jPos = dt.Vector(cmds.xform(str(jnt), q=True, ws=True, t=True)) if not isinstance(target, dt.Vector): tPos = dt.Vector(cmds.xform(str(target), q=True, ws=True, t=True)) else: tPos = target if not upVector: if isinstance(upTarget, PyNode): uPos = dt.Vector(cmds.xform(str(upTarget), q=True, ws=True, t=True)) else: uPos = dt.Vector(upTarget) upV = uPos - jPos if up[0] == '-': upV *= -1.0 upV.normalize() else: upV = dt.Vector(upVector) upV.normalize() aimV = tPos - jPos if aim[0] == '-': aimV *= -1.0 aimV.normalize() # The aim/up order determines if it's aim.cross(up) or up.cross(aim) for the final axis if aim[-1] == 'x' and up[-1] == 'y': mainCross = _forwardCross finalCross = _forwardCross elif aim[-1] == 'x' and up[-1] == 'z': mainCross = _reverseCross finalCross = _reverseCross elif aim[-1] == 'y' and up[-1] == 'z': mainCross = _forwardCross finalCross = _forwardCross elif aim[-1] == 'y' and up[-1] == 'x': mainCross = _reverseCross finalCross = _reverseCross elif aim[-1] == 'z' and up[-1] == 'x': mainCross = _forwardCross finalCross = _forwardCross elif aim[-1] == 'z' and up[-1] == 'y': mainCross = _reverseCross finalCross = _reverseCross finalAxis = mainCross(aimV, upV) finalAxis.normalize() # aimV and upV are probably not perpendicular, but finalAxis was built # perpendicular to both so rebuild upV from aimV and finalAxis #newUp = finalAxis.cross(aimV) newUp = finalCross(finalAxis, aimV) newUp.normalize() axes = [None, None, None] if aim[-1] == 'x': axes[0] = list(aimV) + [0.0] elif aim[-1] == 'y': axes[1] = list(aimV) + [0.0] else: axes[2] = list(aimV) + [0.0] if up[-1] == 'x': axes[0] = list(newUp) + [0.0] elif up[-1] == 'y': axes[1] = list(newUp) + [0.0] else: axes[2] = list(newUp) + [0.0] for i, v in enumerate(axes): if not v: axes[i] = list(finalAxis) + [0.0] axes.append(list(jnt.t.get()) + [1.0]) r = core.math.eulerFromMatrix(axes, degrees=True) # Temporarily unparent children and clear orientation. with core.dagObj.TempWorld(jnt): with core.dagObj.Solo(jnt): if jnt.type() == 'joint': jnt.r.set(0, 0, 0) jnt.jo.set(r) else: jnt.r.set(r)
def check(cls, jnt): if cls.zero < abs(cmds.xform(str(jnt), q=True, ws=True, t=True)[0]) < cls.tolerance: cls.offcenter.append(jnt)
def get_old(mesh): ''' Creates as dictionary that looks like the following: { 'weights': [ ], # index is vertex index, value is list of bone, weight pairs [0] = [ ('j1', .75), ('j2', .25) ]... 'joints': { 'j1': [parent, global_x, global_y, global_z] ... } } ''' ''' DEBUG from pdil.core import capi from maya.api.OpenMayaAnim import MFnSkinCluster ''' skinClusterName = mel.findRelatedSkinCluster(mesh) skinClusterMObj = capi.asMObject( skinClusterName ) skinFn = MFnSkinCluster( skinClusterMObj.object() ) #construct a dict mapping joint names to joint indices jointApiIndices = {} for jointDagMObj in skinFn.influenceObjects(): jointApiIndices[ skinFn.indexForInfluenceObject( jointDagMObj ) ] = jointDagMObj.partialPathName() weightListPlug = skinFn.findPlug( 'weightList', True ) weightListObj = weightListPlug.attribute() weightsPlug = skinFn.findPlug( 'weights', True ) weights = [None] * mesh.vtx.count() # Prebuilding the whole range is nearly instant, appending is probably slower # since it will trigger resizing. for vertIdx in xrange(mesh.vtx.count()): # noqa # We need to use the api to query the physical indices used weightsPlug.selectAncestorLogicalIndex( vertIdx, weightListObj ) activeJointIndices = weightsPlug.getExistingArrayAttributeIndices() # Values = cmds_getAttr( baseFmtStr % vertIdx + '.weights' )[0] # api 2.0 is 0.09 instead of 0.25 values = [weightsPlug.elementByLogicalIndex(i).asDouble() for i in activeJointIndices] try: # If `i` isn't in jointApiIndices, that value is skipped. Not sure why these garbage values are just left behind... weights[vertIdx] = [ (jointApiIndices[idx], v) for idx, v in zip( activeJointIndices, values ) if idx in jointApiIndices] except Exception: raise ''' weights[vertIdx] = [] # This gets hit when an influence object has been removed for i, v in zip(activeJointIndices, values): if v > 0.000001: weights[vertIdx].append( (jointApiIndices[i], v) ) ''' # Prune out the unused joints (Maybe make an option?) joints = {} requiredJoints = set() for wgt in weights: for j, v in wgt: requiredJoints.add(j) # Save the joint's parent and worldspace position, for possible future use/issue detection. for j in requiredJoints: parent = cmds.listRelatives(j, p=True) joints[j] = [parent[0] if parent else None] + cmds.xform(j, q=True, ws=True, t=True) return {'weights': weights, 'joints': joints}