Maya python API: set Vertex Colors

Question:

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)
Asked By: johancc

||

Answers:

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()
Answered By: johancc
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.