Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- bl_info = {
- "name": "Assign random vertex color to each loose part of a mesh",
- "author": "lemon",
- "version": (1, 0),
- "blender": (2, 78, 0),
- "location": "Properties Editor > Object data",
- "description": "",
- "warning": "",
- "wiki_url": "",
- "category": "Mesh"}
- import bpy
- import time
- import random
- from mathutils import Color
- def LoosePartsMakeVertPaths( verts, edges ):
- #Initialize the path with all vertices indexes
- result = {v.index: set() for v in verts}
- #Add the possible paths via edges
- for e in edges:
- result[e.vertices[0]].add(e.vertices[1])
- result[e.vertices[1]].add(e.vertices[0])
- return result
- def LoosePartsFollowEdges( startingIndex, paths ):
- current = [startingIndex]
- result = set( current )
- follow = True
- while follow:
- #Get indexes that are still in the paths
- eligible = set( [ind for ind in current if ind in paths] )
- if len( eligible ) == 0:
- follow = False #Stops is no more
- else:
- #Get the corresponding links
- next = [paths.pop( i ) for i in eligible]
- #Get the new links as new inputs
- current = set( [ind for sub in next for ind in sub] )
- result = result.union( current )
- return result
- def LoosePartsCountIslands( obj ):
- #Prepare the paths/links from each vertex to others
- paths = LoosePartsMakeVertPaths( obj.data.vertices, obj.data.edges )
- found = True
- n = 0
- while found:
- try:
- #Get one input as long there is one
- startingIndex = next( iter( paths.keys() ) )
- n = n + 1
- #Deplete the paths dictionary following this starting index
- LoosePartsFollowEdges( startingIndex, paths )
- except:
- found = False
- return n
- def LoosePartGetIslands( obj ):
- paths = LoosePartsMakeVertPaths( obj.data.vertices, obj.data.edges )
- result = []
- found = True
- while found:
- try:
- #Get one input as long there is one
- startingIndex = next( iter( paths.keys() ) )
- #Deplete the paths dictionary following this starting index and append the result
- result.append( LoosePartsFollowEdges( startingIndex, paths ) )
- except:
- found = False
- return result
- def RandomColor( rnd ):
- return Color( (rnd.random(), rnd.random(), rnd.random()) )
- def RandomColors( rnd, count ):
- return [RandomColor( rnd ) for i in range( count )]
- def ColorFromVertexIndex( vertexIndex, looseParts, colors ):
- for c, lp in zip( colors, looseParts ):
- if vertexIndex in lp:
- return c
- return Color()
- def RandomVertexColorsByLooseParts( obj, vcolName, useSeed, seed ):
- rnd = random.Random()
- if useSeed:
- rnd.seed( seed )
- mesh = obj.data
- #Create vertex colors if it does not already exist
- if vcolName not in mesh.vertex_colors:
- mesh.vertex_colors.new( vcolName )
- #Update it so that it is available below
- mesh.vertex_colors.update()
- #Get the vertex colors
- vertexColors = mesh.vertex_colors[vcolName]
- #Get loose parts
- looseParts = LoosePartGetIslands( obj )
- #Generate random colors
- colors = RandomColors( rnd, len(looseParts) )
- mesh.loops.update()
- #Follow the loops
- for i, vertexIndex in enumerate( [loop.vertex_index for loop in mesh.loops] ):
- #Assign vertex colors from loop index and vertex index
- vertexColors.data[i].color = ColorFromVertexIndex( vertexIndex, looseParts, colors )
- def InitProperties():
- bpy.types.Scene.VertexColorsName = bpy.props.StringProperty( name = "Vertex colors", description = "Vertex colors to use or create", default = "Col" )
- bpy.types.Scene.VertexColorsUseSeed = bpy.props.BoolProperty( name = "Use seed", description = "Use fixed seed to generate random values" )
- bpy.types.Scene.VertexColorsSeed = bpy.props.IntProperty( name = "Seed", description = "Seed for random values" )
- bpy.types.Scene.VertexColorsAllSelected = bpy.props.BoolProperty( name = "All selected objects", description = "Apply to all selected object or only active one" )
- class RndVColToLoosePartsPanel(bpy.types.Panel):
- bl_label = "Random vcol to loose parts"
- bl_space_type = "PROPERTIES";
- bl_region_type = "WINDOW";
- bl_context = ""
- @classmethod
- def poll(self, context):
- return context.object and context.scene
- def draw(self,context):
- layout = self.layout
- scn = context.scene
- layout.prop( scn, 'VertexColorsName', icon='GROUP_VCOL' )
- layout.prop( scn, 'VertexColorsUseSeed' )
- layout.prop( scn, 'VertexColorsSeed' )
- layout.operator( "rndvcoltolooseparts.ope")
- layout.prop( scn, 'VertexColorsAllSelected' )
- class RndVColToLooseParts(bpy.types.Operator):
- bl_idname="rndvcoltolooseparts.ope"
- bl_label="Generate random vcol to each loose parts"
- def execute(self, context):
- scene = context.scene
- obj = context.object
- if scene and obj and obj.type == 'MESH':
- prevMode = obj.mode
- bpy.ops.object.mode_set( mode='OBJECT', toggle=False )
- if scene.VertexColorsAllSelected:
- for obj in [obj for obj in context.selected_objects if obj.type == 'MESH']:
- RandomVertexColorsByLooseParts( obj, scene.VertexColorsName, scene.VertexColorsUseSeed, scene.VertexColorsSeed )
- else:
- RandomVertexColorsByLooseParts( obj, scene.VertexColorsName, scene.VertexColorsUseSeed, scene.VertexColorsSeed )
- bpy.ops.object.mode_set( mode=prevMode, toggle=False )
- return {'FINISHED'}
- def register():
- InitProperties()
- bpy.utils.register_class(RndVColToLooseParts)
- bpy.utils.register_class(RndVColToLoosePartsPanel)
- def unregister():
- bpy.utils.unregister_class(RndVColToLooseParts)
- bpy.utils.unregister_class(RndVColToLoosePartsPanel)
- if __name__ == "__main__":
- register()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement