Skip to content

Instantly share code, notes, and snippets.

@gregoiredehame
Last active September 27, 2024 04:11
Show Gist options
  • Select an option

  • Save gregoiredehame/a19e037b8015610a15ce33fbef3b3e0d to your computer and use it in GitHub Desktop.

Select an option

Save gregoiredehame/a19e037b8015610a15ce33fbef3b3e0d to your computer and use it in GitHub Desktop.
from __future__ import annotations
import maya.cmds as cmds
import maya.api.OpenMaya as om2
import math
def get_weights() -> list:
"""
function that will return a list of float value based on current soft selection.
"""
try:
soft_selection = om2.MGlobal.getRichSelection()
selection = soft_selection.getSelection()
iter = om2.MItSelectionList(selection, om2.MFn.kMeshVertComponent)
elements = []
eladd = elements.append
while not iter.isDone():
dag_path, comp = iter.getComponent()
dag_path.pop()
node = dag_path.fullPathName()
fn_comp = om2.MFnSingleIndexedComponent(comp)
for i in range(fn_comp.elementCount):
eladd([node, fn_comp.getElements()[i], fn_comp.weight(i).influence])
iter.next()
return elements
except:
return None
def set_weights(cluster:om2.MFnDependencyNode=None, weights:list=None) -> bool:
"""
function that will set the current cluster weights based on given cluster (om2.MFnDependencyNode)
Args:
cluster: (om2.MFnDependencyNode): - cluster fn
weights: (list): - weights to set on the clusters
"""
weight_list_plug = cluster.findPlug('weightList', 0)
weight_list_attr = weight_list_plug.attribute()
weight_plug = cluster.findPlug('weights', 0)
weight_attr = weight_plug.attribute()
for weight in weights:
weight_plug.selectAncestorLogicalIndex(0, weight_list_attr)
influence_plug = om2.MPlug(weight_plug)
influence_plug.selectAncestorLogicalIndex(int(weight[1]), weight_attr)
influence_plug.setDouble(weight[2])
return True
def remove_weights(cluster:om2.MFnDependencyNode=None, mesh:str=None) -> bool:
"""
function that will reset the 0 every single weights on the current cluster
Args:
cluster: (om2.MFnDependencyNode): - cluster fn
mesh: (str): - string mesh to remove weights from.
"""
weight_list_plug = cluster.findPlug('weightList',0)
weight_list_attr = weight_list_plug.attribute()
weight_plug = cluster.findPlug('weights',0)
weight_attr = weight_plug.attribute()
for vid in range(len(cmds.ls('%s.vtx[*]'% mesh, flatten=True))):
weight_plug.selectAncestorLogicalIndex(0, weight_list_attr)
influence_plug = om2.MPlug(weight_plug)
influence_plug.selectAncestorLogicalIndex(int(vid), weight_attr)
influence_plug.setDouble(0)
return True
def get_components_matrices(components:list=None) -> om2.MMatrixArray:
"""
function that will return a MMatrixArray of every single selected components in worldspace
Args:
components: (list): - list of component to return matrices from.
"""
matrices = om2.MMatrixArray()
for component in components:
component = om2.MGlobal.getSelectionListByName(component)
__, id = component.getComponent(0)
component_id = om2.MFnSingleIndexedComponent(id).getElements()[0]
normal = om2.MFnMesh(component.getDagPath(0)).getVertexNormal(component_id, 0, om2.MSpace.kWorld)
point = om2.MFnMesh(component.getDagPath(0)).getPoint(component_id, om2.MSpace.kWorld)
matrices.append(om2.MMatrix((normal.x, normal.y, normal.z, 0, 0, 1, 0, 0, 0, 0, 1, 0, point.x, point.y, point.z, point.w)))
return matrices
def get_average_matrix(matrices:om2.MMatrixArray=None) -> om2.MMatrix:
"""
function that will return the average matrix from a given MMatrixArray
(this will only being used if there is more than one component selected.)
Args:
matrices: (om2.MMatrixArray): - list of component to return matrices from.
"""
num_matrices = len(matrices)
sum_matrix = om2.MMatrix()
for mat in matrices:
sum_matrix += mat
avg_matrix_elements = [sum_matrix[i] / num_matrices for i in range(16)]
return om2.MTransformationMatrix(om2.MMatrix(avg_matrix_elements))
def create() -> bool:
"""
function that will do the job
"""
weights = get_weights()
if weights:
matrices = get_components_matrices(cmds.ls(selection=True, flatten=True))
if matrices:
matrix = om2.MTransformationMatrix(matrices[0]) if len(matrices) == 1 else get_average_matrix(matrices)
euler = matrix.rotation(asQuaternion=False)
mesh = vertices[-1].split(".")[0]
dag_path = om2.MGlobal.getSelectionListByName(mesh).getDagPath(0)
dag_path.extendToShape()
mfn_mesh = om2.MFnMesh(dag_path)
cluster, cluster_handle = cmds.cluster(mesh, relative=True)
cluster_selection = om2.MGlobal.getSelectionListByName(cluster)
cluster_depend = cluster_selection.getDependNode(0)
cluster_fn = om2.MFnDependencyNode(cluster_depend)
remove_weights(cluster_fn, mesh)
set_weights(cluster_fn, weights)
offset = cmds.createNode("transform", name="%sOffset"% cluster)
cmds.parent(cluster_handle, offset, relative=True)
cmds.setAttr("%s.translate"% offset, *matrix.translation(om2.MSpace.kWorld), type="float3")
cmds.setAttr("%s.rotate"% offset, *(math.degrees(euler.x), math.degrees(euler.y), math.degrees(euler.z)), type="float3")
cmds.connectAttr("%s.worldInverseMatrix[0]"% offset, "%s.bindPreMatrix"% cluster)
cluster_shape = cmds.ls(cluster_handle, shapes=True, dagObjects=True)[0]
cmds.setAttr("%s.origin"% cluster_shape, 0,0,0)
cmds.setAttr("%s.relative"% cluster, False)
[cmds.setAttr("%s.%s"% (offset, attribute), lock=True) for attribute in ("translate", "rotate", "scale")]
cmds.makeIdentity(cluster_handle, apply=True, translate=True, rotate=True, scale=True)
return True
om2.MGlobal.displayWarning("unable to query vertices matrix.")
om2.MGlobal.displayWarning("unable to query weights/soft selection.")
if __name__ == "__main__":
create()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment