Search code examples
pythonapimaya

Maya python API: set Vertex Colors


How can I set vertex colors with the Maya python api, given a number of uv shells? So for each shell within a single mesh assign a random vertex color. At the bottom I have the previous code which is too slow in more dense meshes.

signle mesh in maya

def setColors():

    shells = getUvShelList( cmds.ls(sl=1)[0] )

    print ( shells )

    """

    #3 similar objects combined into one

    {0: ['pCube4.map[0]', 'pCube4.map[1]', 'pCube4.map[2]', 'pCube4.map[3]', 'pCube4.map[4]', 'pCube4.map[5]', 'pCube4.map[6]', 'pCube4.map[7]', 'pCube4.map[8]', 'pCube4.map[9]', 'pCube4.map[10]', 'pCube4.map[11]', 'pCube4.map[12]', 'pCube4.map[13]'], 
    1: ['pCube4.map[14]', 'pCube4.map[15]', 'pCube4.map[16]', 'pCube4.map[17]', 'pCube4.map[18]', 'pCube4.map[19]', 'pCube4.map[20]', 'pCube4.map[21]', 'pCube4.map[22]', 'pCube4.map[23]', 'pCube4.map[24]', 'pCube4.map[25]', 'pCube4.map[26]', 'pCube4.map[27]'], 
    2: ['pCube4.map[28]', 'pCube4.map[29]', 'pCube4.map[30]', 'pCube4.map[31]', 'pCube4.map[32]', 'pCube4.map[33]', 'pCube4.map[34]', 'pCube4.map[35]', 'pCube4.map[36]', 'pCube4.map[37]', 'pCube4.map[38]', 'pCube4.map[39]', 'pCube4.map[40]', 'pCube4.map[41]']}

    """
    
    selList2 = om2.MGlobal.getActiveSelectionList()
    dagPath = selList2.getDagPath(0)
    selMesh = om2.MFnMesh(dagPath)
    
    vertList = list(set(selMesh.getVertices()[1]))
    lenVertList = len(vertList)
    
    for shell in shells:
        
    
        selection_shell = shells.get(shell)

        r = [random.random() for i in range(3)]
        tempColor = om2.MColor([r[0],r[1],r[2]])
        vertexColorList = om2.MColorArray(lenVertList, tempColor)
        
        selMesh.setVertexColors(vertexColorList, vertList) 
    

setColors()

My previous code(too slow):

for shell in chunk:

    selection_shell = shells.get(shell)
    
    cmds.select(selection_shell)
    facesSel = cmds.polyListComponentConversion(fromUV=True, toFace=True)
    cmds.select(facesSel)
    r = [random.random() for i in range(3)]
    cmds.polyColorPerVertex(facesSel,rgb=(r[0], r[1], r[2]), cdo=1 )
    
    cmds.select(deselect=1)

Solution

  • Here's what I ended up doing, creating a random color per element within a mesh. Similar to element ID in 3ds max.

    To answer my own question, I had to convert the UV indices to Vertex indices per shell.

    import maya.cmds as cmds
    import maya.api.OpenMaya as om
    from itertools import zip_longest
    from itertools import chain
    import random
    import colorsys
    import time
    import maya.mel as mel
    
    
    
    
    class colorVariationShell():
    
        def __init__(self):
    
            self.setSelection()
            self.setColors()
    
    
        def setSelection(self):
    
            # Get the currently selected mesh.
            self.mSelList = om.MGlobal.getActiveSelectionList()
            self.path = self.mSelList.getDagPath(0)
            self.fnMesh = om.MFnMesh(self.path)
    
    
        def get_progress_bar(self,status_text, max_value):
            try:
                progress_bar = mel.eval("$tmp = $gMainProgressBar")
            except RuntimeError:
                progress_bar = None
    
            if progress_bar:
                cmds.progressBar(
                    progress_bar,
                    edit=True,
                    beginProgress=True,
                    isInterruptable=False,
                    status=status_text,
                    maxValue=max_value
                )
            return progress_bar               
    
    
        def getUvShellsOnObj(self):     
            
            #Get UV Sets
            uvSets = self.fnMesh.getUVSetNames()
            
    
            for uvset in uvSets:
    
                uvShellIds = self.fnMesh.getUvShellsIds(uvset)[1]
                polyVertices = self.fnMesh.getVertices()
                polyUvs = self.fnMesh.getAssignedUVs(uvset)
                
                shells = {}
                
                vertexGroup = []
                
                list_zip = zip(polyVertices[1], polyUvs[1])
                zipped_list = list(list_zip)
    
                main_progress_bar_3 = self.get_progress_bar("Getting UV Shells IDS", len(zipped_list))
                
                for i, n in enumerate(uvShellIds): 
                    if n in shells:
                        shells[n].append(   i  )
                    else:
                        shells[n] = [  ( i ) ]
    
                    cmds.progressBar(main_progress_bar_3, edit=True, step=1)
    
                cmds.progressBar(main_progress_bar_3, edit=True, endProgress=True)
                        
                vertsID = []
                uvsID = []
    
                main_progress_bar = self.get_progress_bar("Gathering UV and Vertex Info", len(zipped_list))
                
                for zipItem in zipped_list:
                    
                    vertsID.append(zipItem[0])
                    uvsID.append(zipItem[1])
    
                    cmds.progressBar(main_progress_bar, edit=True, step=1)
    
                cmds.progressBar(main_progress_bar, edit=True, endProgress=True)
                    
    
                vertex_id_from_shell = {}
    
                
                main_progress_bar_2 = self.get_progress_bar("Passing UV and Vertex data", len(shells))
                for shell in shells:
                    
                    selection_shell = shells.get(shell)
                    
                    for idx, item in enumerate(selection_shell):
                        
                        if item in uvsID:
                            
                            uv_index =  uvsID.index(item)                    
                            vertex_ids = vertsID[uv_index]
    
                            # if the list does not exist, create it
                            if shell not in vertex_id_from_shell:
                                vertex_id_from_shell[shell] = []
                
                            # append to list
                            vertex_id_from_shell[shell].append(vertex_ids)
    
                    cmds.progressBar(main_progress_bar_2, edit=True, step=1)
    
                cmds.progressBar(main_progress_bar_2, edit=True, endProgress=True)
    
            return shells, vertex_id_from_shell
    
    
    
    
        def setColors(self):
            
            shells, target_vertex_id = self.getUvShellsOnObj()
            
            #ammount of different colors
            var = 3
             
            vertexData = {key : [] for key in range(var)}
             
            pool = []
            for val in target_vertex_id.values():
                if not pool:
                    pool = list(range(var))
                    random.shuffle(pool)
                vertexData[pool.pop()].extend(val)
            
            main_progress_bar = self.get_progress_bar("Applying Vertex Colors", len(vertexData))
    
            for vertex_idx, selection_vertex in vertexData.items():
            
                vertexIds = selection_vertex
                lenVertList = len(vertexIds)
                
                
                sat_random = random.uniform(0.5, 1)
                
                increment = 1/len(vertexData)
                
                color_hsv = (vertex_idx*increment, sat_random, vertex_idx*increment+1/len(vertexData))
                
                rgb_color = colorsys.hsv_to_rgb(color_hsv[0],color_hsv[1],color_hsv[2])
                
                 
                
                final_color = om.MColor(rgb_color)
                
    
                vertexColorList = om.MColorArray(lenVertList, final_color)
                
                #apply the color        
                self.fnMesh.setVertexColors(vertexColorList, vertexIds)
    
                cmds.progressBar(main_progress_bar, edit=True, step=1)
    
            cmds.polyOptions(colorShadedDisplay=1)
    
            cmds.progressBar(main_progress_bar, edit=True, endProgress=True)
    
    
    
    start_time = time.time()
    
    colorVariationShell()