Skip to content

Instantly share code, notes, and snippets.

@Pakmanv
Created May 2, 2025 23:31
Show Gist options
  • Select an option

  • Save Pakmanv/09f5586e19ac59beb606eea6193e91ec to your computer and use it in GitHub Desktop.

Select an option

Save Pakmanv/09f5586e19ac59beb606eea6193e91ec to your computer and use it in GitHub Desktop.
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