-
-
Save Pakmanv/09f5586e19ac59beb606eea6193e91ec 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
| import maya.cmds as mc | |
| import maya.OpenMaya as om | |
| def get_original_selection(): | |
| """Retrieve the explicitly selected vertices (original selection).""" | |
| selection = om.MSelectionList() | |
| try: | |
| om.MGlobal.getActiveSelectionList(selection) | |
| except Exception as e: | |
| print(f"Error getting active selection: {e}") | |
| return None | |
| vertices = [] | |
| iter_sel = om.MItSelectionList(selection, om.MFn.kMeshVertComponent) | |
| while not iter_sel.isDone(): | |
| dag_path = om.MDagPath() | |
| component = om.MObject() | |
| try: | |
| iter_sel.getDagPath(dag_path, component) | |
| except: | |
| iter_sel.next() | |
| continue | |
| dag_path.pop() # Get to the transform level | |
| node = dag_path.fullPathName() | |
| fn_comp = om.MFnSingleIndexedComponent(component) | |
| for i in range(fn_comp.elementCount()): | |
| vertex_index = fn_comp.element(i) | |
| vertex_name = f"{node}.vtx[{vertex_index}]" | |
| vertices.append(vertex_name) | |
| iter_sel.next() | |
| print(f"Original selection: {len(vertices)} vertices: {vertices}") | |
| return vertices | |
| def get_soft_selection_weights(): | |
| """Retrieve soft selection vertices and weights.""" | |
| selection = om.MSelectionList() | |
| soft_selection = om.MRichSelection() | |
| try: | |
| om.MGlobal.getRichSelection(soft_selection, True) # True to include soft selection | |
| soft_selection.getSelection(selection) | |
| except Exception as e: | |
| print(f"Error getting rich selection: {e}") | |
| return None, None | |
| vertices = [] | |
| weights = [] | |
| iter_sel = om.MItSelectionList(selection, om.MFn.kMeshVertComponent) | |
| while not iter_sel.isDone(): | |
| dag_path = om.MDagPath() | |
| component = om.MObject() | |
| try: | |
| iter_sel.getDagPath(dag_path, component) | |
| except: | |
| iter_sel.next() | |
| continue | |
| dag_path.pop() # Get to the transform level | |
| node = dag_path.fullPathName() | |
| fn_comp = om.MFnSingleIndexedComponent(component) | |
| for i in range(fn_comp.elementCount()): | |
| vertex_index = fn_comp.element(i) | |
| vertex_name = f"{node}.vtx[{vertex_index}]" | |
| weight = fn_comp.weight(i).influence() | |
| vertices.append(vertex_name) | |
| weights.append(weight) | |
| iter_sel.next() | |
| print(f"Soft selection: {len(vertices)} vertices with weights: {weights}") | |
| return vertices, weights | |
| def calculate_centroid(vertices): | |
| """Calculate the centroid of given vertices.""" | |
| if not vertices: | |
| print("No vertices provided for centroid. Using world origin.") | |
| return [0.0, 0.0, 0.0] | |
| positions = [] | |
| for vertex in vertices: | |
| try: | |
| pos = mc.pointPosition(vertex, world=True) | |
| positions.append(pos) | |
| except Exception as e: | |
| print(f"Error getting position for {vertex}: {e}") | |
| continue | |
| if not positions: | |
| print("No valid positions for centroid. Using world origin.") | |
| return [0.0, 0.0, 0.0] | |
| centroid = [0.0, 0.0, 0.0] | |
| for pos in positions: | |
| for i in range(3): | |
| centroid[i] += pos[i] | |
| return [c / len(positions) for c in centroid] | |
| def soft_selection_to_cluster(): | |
| """Convert soft selection to cluster with handle and pivot at original selection.""" | |
| # Check if soft selection is enabled | |
| if not mc.softSelect(q=True, softSelectEnabled=True): | |
| mc.warning("Soft selection is not enabled. Please enable soft selection.") | |
| return False | |
| # Get original selection (explicitly selected vertices) | |
| original_vertices = get_original_selection() | |
| if not original_vertices: | |
| mc.warning("No original vertex selection found. Please select vertices.") | |
| return False | |
| # Get soft selection vertices and weights | |
| vertices, weights = get_soft_selection_weights() | |
| if not vertices or not weights: | |
| mc.warning("No valid soft selection found. Please select vertices with soft selection.") | |
| return False | |
| # Calculate centroid of original selection for pivot and origin | |
| centroid = calculate_centroid(original_vertices) | |
| print(f"Original selection centroid for pivot and origin: {centroid}") | |
| # Create a cluster on the soft-selected vertices | |
| try: | |
| mc.select(vertices, r=True) # Select all soft-selected vertices | |
| cluster = mc.cluster(n="SoftSelCluster", relative=True) | |
| cluster_name = cluster[0] # Cluster node | |
| cluster_handle = cluster[1] # Cluster handle | |
| except Exception as e: | |
| mc.error(f"Failed to create cluster: {e}") | |
| return False | |
| # Apply weights to the cluster | |
| for vertex, weight in zip(vertices, weights): | |
| try: | |
| mc.percent(cluster_name, vertex, v=weight) | |
| # Verify weight application | |
| applied_weight = mc.percent(cluster_name, vertex, q=True, v=True) | |
| if abs(applied_weight[0] - weight) > 0.01: | |
| print(f"Warning: Weight mismatch for {vertex}: set {weight}, got {applied_weight[0]}") | |
| except Exception as e: | |
| mc.warning(f"Failed to set weight for {vertex}: {e}") | |
| # Set the pivot and cluster handle shape origin to the centroid without translating | |
| try: | |
| # Set the pivot to the centroid | |
| mc.xform(cluster_handle, pivots=centroid, worldSpace=True) | |
| # Set the cluster handle shape's origin to the centroid | |
| cluster_handle_shape = f"{cluster_handle}Shape" | |
| if mc.objExists(cluster_handle_shape): | |
| mc.setAttr(f"{cluster_handle_shape}.originX", centroid[0]) | |
| mc.setAttr(f"{cluster_handle_shape}.originY", centroid[1]) | |
| mc.setAttr(f"{cluster_handle_shape}.originZ", centroid[2]) | |
| print(f"Cluster handle shape origin set to: {centroid}") | |
| else: | |
| mc.warning(f"Cluster handle shape {cluster_handle_shape} not found.") | |
| # Ensure no translation or rotation is applied | |
| mc.setAttr(f"{cluster_handle}.translateX", 0) | |
| mc.setAttr(f"{cluster_handle}.translateY", 0) | |
| mc.setAttr(f"{cluster_handle}.translateZ", 0) | |
| mc.setAttr(f"{cluster_handle}.rotateX", 0) | |
| mc.setAttr(f"{cluster_handle}.rotateY", 0) | |
| mc.setAttr(f"{cluster_handle}.rotateZ", 0) | |
| print(f"Cluster handle pivot set to {centroid}, transforms and rotations zeroed.") | |
| except Exception as e: | |
| mc.warning(f"Failed to configure cluster handle: {e}") | |
| mc.select(cluster_handle, r=True) # Select cluster handle | |
| print(f"Cluster {cluster_name} created with soft selection influence for {len(vertices)} vertices.") | |
| return True | |
| def create_vvclustertool_ui(): | |
| """Create the Soft Select to Cluster UI.""" | |
| # Delete the window if it already exists | |
| if mc.window("VVclustertool", exists=True): | |
| mc.deleteUI("VVclustertool") | |
| # Create the window | |
| window = mc.window("VVclustertool", title="Soft Select to Cluster", widthHeight=(300, 100), sizeable=False) | |
| # Create the layout | |
| mc.columnLayout(adjustableColumn=True, rowSpacing=10) | |
| # Add instructions | |
| mc.text(label="Select vertices, enable soft selection, then click below:") | |
| # Add the button | |
| mc.button(label="Softselect to Cluster", command=lambda x: soft_selection_to_cluster(), height=40) | |
| # Show the window | |
| mc.showWindow(window) | |
| # Execute the UI creation | |
| create_vvclustertool_ui() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment