Search code examples
pythonmaya

How to randomly assign color to verts individually inside a "for loop" but not to the whole mesh?


I have a piece of code which is supposed to grab all verts of an object and then through the use of "for loop" assign them a random color value inside a grayscale range.

The following code selects every vert of the mesh one by one but does not assign a color to each one of them. Instead it assigns a color to all of them at the same time filling the whole object with a uniform color.

import maya.cmds as cmds
import functools
import random

colorList =cmds.ls('colorSet*' )
sphereList = cmds.ls( 'mySphere*' )
if len( sphereList ) > 0:
    cmds.delete( sphereList)

result = cmds.polySphere ( r=50, sx=random.randrange(10, 100), sy=random.randrange(10,100), name='mySphere#' )


cmds.polyColorSet ( create=True, colorSet='colorSet1')

def get_random_vertexes():
        percent = 1
        vertexes = []
        for obj in cmds.ls(sl=1, long=1):
            indexes = range(cmds.polyEvaluate(obj, vertex=1))
            random.shuffle(indexes)
            indexes = indexes[:int(percent*len(indexes))]
            for i in range(len(indexes)):
                indexes[i] = obj+'.vtx['+str(indexes[i])+']'
                brightness = random.uniform(0.1,1.0)
                rgb = (brightness, brightness, brightness)
                cmds.polyColorPerVertex (rgb=rgb)
            vertexes.extend(indexes)
        cmds.select(vertexes, r=1)

get_random_vertexes()

Instead of having a noisy range of color values on the mesh it is filled with a flat color. How do I make sure each vert gets assigned a color as it's being selected while not touching other verts?


Solution

  • The main issue is that you don't pass anything to cmds.polyColorPerVertex so that every time you call it, it colors whatever is currently selected (in this case all verts from the sphere). If you pass a vert though that function it will set it on the single vert as expected:

    import maya.cmds as cmds
    import random
    
    
    sphereList = cmds.ls('mySphere*')
    if sphereList:  # Can shorten if statement.
        cmds.delete(sphereList)
    
    new_obj, _ = cmds.polySphere (r=50, sx=random.randrange(10, 20), sy=random.randrange(10, 20), name='mySphere#')
    cmds.setAttr('{}.displayColors'.format(new_obj), True)  # Display vert colors.
    
    cmds.polyColorSet(new_obj, create=True, colorSet='colorSet1')
    
    def set_random_vertexes(percent=1):  # Move percent as a parameter so it's not hard-coded.
        vertexes = []
    
        for obj in cmds.ls(sl=1, long=1):
            all_verts = cmds.ls('{}.vtx[*]'.format(obj), flatten=True)  # Use `cmds.ls` with `flatten` to get a list of all vertexes.
            random.shuffle(all_verts)
            verts = all_verts[:int(percent * len(all_verts))]
    
            for vert in verts:
                brightness = random.uniform(0.1, 1.0)
                rgb = (brightness, brightness, brightness)
                cmds.polyColorPerVertex(vert, rgb=rgb)  # Pass vert's name to change its color.
    
            vertexes.extend(verts)
    
        cmds.select(vertexes, r=1)
    
    set_random_vertexes()
    

    I also included a few optimizations in there. You might want to consider changing the name of the function get_random_vertexes as it feels misleading by setting vertexes instead of returning a list of them.