Search code examples
pythonmayamel

Select Subobjects in maya python


I am currently trying to give each subobject of a DAG node a different color. It works when I am selecting each of those subobject/elements (but not all)in the component select mode and then run the script over it. But selecting the mesh as whole, does not work for me. I already tried different kinds of listRelatives but none worked. I can get into the object and get each vertices, but they are not grouped by connectivity.

    def assignDMat(self,*args):
    #selection = self.selector()
    selection = cmds.ls(selection=True)
    for j in range(0, len(selection)):
        cmds.polyColorPerVertex(selection[j], r=0,  g=0, b=0, cdo=True)
        cmds.polyColorPerVertex(selection[j], r=random.uniform(0,1), cdo=True)

New code:

import maya.cmds as cmds
import random

selection = cmds.ls(selection=True)

cmds.polySeparate(selection)


for i in range(0,len(selection)):
    obj=cmds.listRelatives(selection[i])
    print(len(obj))
    for j in range(0,len(obj)-1):
        cmds.polyColorPerVertex(obj[j], r=0,  g=0, b=0, cdo=True)
        cmds.polyColorPerVertex(obj[j], r=random.uniform(0,1), cdo=True)

cmds.polyUnite(("polySurface*"), n="Result", ch=False)

Intended Result


Solution

  • Using separate then re-merging the meshes can cause a lot of unexpected issues, some which you have already ran into, so it's best to avoid that.

    Instead we can create a function that will return all separate shells of an object by returning a bunch of lists of their face indexes. This can be done with cmds.polySelect to pass a face index to it, then it'll select the whole shell. Since the shell is now selected we can now just collect the new selection and continue on to get the next shell. Then with that it's easy to just loop through each of them and color them with cmds.polyColorPerVertex.

    Here's an example that will create a random amount of poly spheres, combine them all, then set a random color to each shell:

    import random
    import maya.cmds as cmds
    
    
    # Just makes a bunch of random spheres, combines them, then returns the new mesh.
    def make_bunch_of_spheres():
        meshes = []
    
        for i in range(random.randint(20, 50)):
            meshes.append(cmds.polySphere()[0])
            cmds.move(random.randint(-20, 20), random.randint(-20, 20), random.randint(-20, 20), meshes[-1])
    
        return cmds.polyUnite(meshes, constructionHistory=False)[0]
    
    
    def get_shell_faces():
        shells = []  # We'll be putting in lists of face indexes in here later. Each sub-list will represent a separate shell.
    
        sel = cmds.ls(sl=True)
    
        for obj in sel:
            faces = cmds.ls(obj + ".f[*]", flatten=True)  # Get all face indexes from the object.
    
            for face in faces:
                index = int(face.split("[")[1].rstrip("]"))  # Extract the faces index number.
                cmds.polySelect(obj, extendToShell=index)  # Use the face's index to select the whole shell.
    
                new_faces = cmds.ls(sl=True, flatten=True)  # Now that the shell is selected, capture its faces.
                shells.append(new_faces)  # Append the face's as a new shell.
    
                # Remove indexes from the new shell from this current loop, to optimize, and to avoid adding duplicate shells.
                for new_face in new_faces:
                    if new_face in faces:
                        faces.pop(faces.index(new_face))
    
        cmds.select(sel)  # Restore selection.
    
        return shells
    
    
    # Create a bunch of combined spheres then select it.
    new_mesh = make_bunch_of_spheres()
    cmds.select(new_mesh)
    
    shells = get_shell_faces()  # Get shells from selection.
    
    # Color each shell!
    for shell in shells:
        cmds.polyColorPerVertex(shell, r=random.random(),  g=random.random(), b=random.random(), cdo=True)
    

    Example