Last active
September 27, 2024 04:11
-
-
Save gregoiredehame/a19e037b8015610a15ce33fbef3b3e0d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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