def __init__(self, parent, vertex): ui.QWidget.__init__(self, parent) # variables self.vertex = vertex self.mesh, _ = vertex.split(".", 1) self.skinCluster = utils.getSkinCluster(self.mesh) # get skinned data influences = cmds.skinPercent(self.skinCluster, vertex, query=True, transform=None) values = cmds.skinPercent(self.skinCluster, vertex, query=True, value=True) # order data data = zip(values, influences) data.sort() data.reverse() # create layout layout = ui.QVBoxLayout(self) layout.setContentsMargins(3, 3, 3, 3) layout.setSpacing(3) # create divider ui.addDivider(self, layout) # create label self.label = VertexLabelWidget(self, vertex) layout.addWidget(self.label) # create divider ui.addDivider(self, layout) # create frame self.frame = VertexInfluencesWidget(self, self.skinCluster, data) self.frame.signal.connect(self.setWeights) layout.addWidget(self.frame) # connect influences toggle self.label.signal.connect(self.frame.displayInfluences) self.frame.warningSignal.connect(self.label.displayWarning) # force display self.frame.displayMaxInfluences()
def getSkinnedVertices(): """ Get all of the skinned vertices that are currently selected. Loop over the current selection and see if the vtx suffix is found indicating a component selection. Then the mesh if extracted from this component and checked if a skinCluster is attached. If the selection meets these criteria it will be added to the list. :return: List of selected skinned vertices :rtype: list of strings """ skinnedVertices = [] selection = cmds.ls(sl=True, fl=True, l=True) or [] for sel in selection: if not sel.count(".vtx"): continue mesh, _ = sel.split(".", 1) if utils.getSkinCluster(mesh): skinnedVertices.append(sel) return skinnedVertices
def setSkinWeights(mesh, meshData, influences, filler=None): """ Calculate and set the new skin weights. If no skin cluster is attached to the mesh, one will be created and all weights will be set to 1 with the filler influence. If a skin cluster does exist, the current weights will be used to blend the new weights. Maintaining of maximum influences and normalization of the weights will be taken into account if these attributes are set on the skin cluster. meshData = { mesh:{ {index:{ influence:weight, influence:weight, }, {index:{ influence:weight, influence:weight, }, } } :param str mesh: :param dict meshData: skinning data for the mesh :param list influences: list of (new) influences :param str filler: Filler joint if no skin cluster is detected """ with utils.UndoChunkContext(): skinCluster = utils.getSkinCluster(mesh) # bind skin if not skinCluster: influences.append(filler) skinCluster = cmds.skinCluster(mesh, influences, omi=True, mi=4, tsb=True)[0] # set weights with filler cmds.skinPercent(skinCluster, "{0}.vtx[*]".format(mesh), transformValue=[(filler, 1)]) # add influences else: filler = None utils.addInfluences(skinCluster, influences) # get skinCluster data normalizeWeights = cmds.getAttr( "{0}.normalizeWeights".format(skinCluster)) maxInfluences = cmds.getAttr("{0}.maxInfluences".format(skinCluster)) maintainMaxInfluences = cmds.getAttr( "{0}.maintainMaxInfluences".format(skinCluster)) # loop indices for index, weights in meshData.iteritems(): vertex = "{0}.vtx[{1}]".format(mesh, index) total = sum(weights.values()) if filler and total < 1: # add filler weight weights[filler] = 1 - total elif not filler and total < 1: multiplier = 1 - total # query existing transforms = cmds.skinPercent(skinCluster, vertex, query=True, transform=None) transforms = cmds.ls(transforms, l=True) values = cmds.skinPercent(skinCluster, vertex, query=True, value=True) # add normalized existing weights for t, v in zip(transforms, values): if not t in weights.keys(): weights[t] = 0 weights[t] += v * multiplier if maintainMaxInfluences: # maintain influences, set excess influences to 0.0 temp = zip(weights.values(), weights.keys()) excess = sorted(temp, reverse=True)[maxInfluences:] for v, t in excess: weights[t] = 0.0 if normalizeWeights == 1: # normalize all weights total = sum(weights.values()) multiplier = 1 / total for t, v in weights.iteritems(): weights[t] = v * multiplier # set weights weights = [(t, v) for t, v in weights.iteritems()] cmds.skinPercent(skinCluster, vertex, transformValue=weights)
def deLinearSkinWeights(vertices, method): """ Loop over all of the provided vertices. Loop over all of the vertices and see if these vertices are deformed by a skin cluster. If this is the case, the weights will be de-linearized by the function provided. This function is found in the tweening module using :func:`getTweeningMethod`. :param list vertices: List of vertices :param str method: De-linearization method """ func = getTweeningMethod(method) if not func: raise ValueError("Tweening method is not supported.") data = {} objects = list(set([vtx.split(".")[0] for vtx in vertices])) with utils.UndoChunkContext(): for obj in objects: # get skin cluster sk = utils.getSkinCluster(obj) if not sk: continue # get indices indices = [ getIndexFromString(vtx) for vtx in vertices if vtx.startswith(obj) ] # get api objects meshObj = utils.asMObject(obj) meshDag = utils.asMDagPath(meshObj) meshDag.extendToShape() skObj = utils.asMObject(sk) skMfn = OpenMayaAnim.MFnSkinCluster(skObj) # get weights components = utils.asComponent(indices) weightsAll, num = utils.getSkinWeights( meshDag, skMfn, components ) # split weights weightChunks = splitByInfluences(weightsAll, num) for i, weights in enumerate(weightChunks): # calculate per vertex weights weights = utils.normalizeWeights(weights) weights = [func(w) for w in weights] weights = utils.normalizeWeights(weights) # set weights for j, w in enumerate(weights): cmds.setAttr( "{0}.weightList[{1}].weights[{2}]".format( sk, indices[i], j ), w )