-
-
Save p2or/ab314836285579cdfdb5d7848af8ee5c to your computer and use it in GitHub Desktop.
HSV version of https://blender.stackexchange.com/a/136926/ #Blender
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bl_info = { | |
"name": "Mesh Islands Random Vertex Color", | |
"author": "batFINGER, p2or", | |
"version": (1, 0), | |
"blender": (2, 80, 0), | |
"location": "F3 Search or Vertex Paint > Paint > Random Vertex Colors", | |
"description": "Assign random vertex color to mesh islands", | |
"warning": "", | |
"wiki_url": "", | |
"category": "Mesh"} | |
import bpy | |
import bmesh | |
from random import uniform, sample | |
from bpy.props import StringProperty, BoolProperty, FloatVectorProperty | |
from mathutils import Vector | |
from colorsys import hsv_to_rgb | |
def walk_island(vert): | |
''' walk all un-tagged linked verts ''' | |
vert.tag = True | |
yield (vert) | |
linked_verts = [ | |
e.other_vert(vert) for e in vert.link_edges | |
if not e.other_vert(vert).tag] | |
for v in linked_verts: | |
if v.tag: | |
continue | |
yield from walk_island(v) | |
def get_islands(bm, verts=[]): | |
def tag(verts, switch): | |
for v in verts: | |
v.tag = switch | |
tag(bm.verts, True) | |
tag(verts, False) | |
ret = {"islands": []} | |
verts = set(verts) | |
while verts: | |
v = verts.pop() | |
verts.add(v) | |
island = set(walk_island(v)) | |
faces = set( | |
f for x in island for f in x.link_faces | |
if all(v.tag for v in f.verts)) | |
edges = set( | |
e for x in island for e in x.link_edges | |
if all(v.tag for v in e.verts)) | |
ret["islands"].append(island.union(edges).union(faces)) | |
tag(island, False) # remove tag = True | |
verts -= island | |
return ret | |
class BMIslands(list): | |
def __init__(self, bm): | |
self.extend(BMeshIsland(i, island) for i, island in enumerate(get_islands(bm, verts=bm.verts)["islands"])) | |
self.sort(key=lambda i: (i.co.x, i.co.y)) | |
for i, island in enumerate(self): | |
island.index = i | |
class BMeshIsland: | |
def __init__(self, index, geom): | |
self.index = index | |
self.verts = [e for e in geom if isinstance(e, bmesh.types.BMVert)] | |
self.co = sum([v.co for v in self.verts], Vector()) / len(self.verts) | |
self.faces = [e for e in geom if isinstance(e, bmesh.types.BMFace)] | |
class MESH_OT_random_island_vertex_color(bpy.types.Operator): | |
"""Generate random Vertex Colors per Island""" | |
bl_idname = "mesh.random_island_vert_color" | |
bl_label = "Random Color per Vertex Island" | |
bl_options = {'REGISTER', 'UNDO'} | |
islands = None | |
bm = None | |
layer: StringProperty( | |
name="Layer", default="Random") | |
satuation: FloatVectorProperty( | |
size=2, default=(0.6,1.0), max=1.0, min=0.0) | |
lightness: FloatVectorProperty( | |
size=2, default=(0.6,1.0), max=1.0, min=0.0) | |
shuffle: BoolProperty( | |
name="Shuffle", default=True) | |
@classmethod | |
def poll(cls, context): | |
return(context.object | |
and context.object.mode == 'OBJECT' | |
or context.object.mode == 'VERTEX_PAINT' | |
and context.object.type == 'MESH') | |
def main(self, ob): | |
me = ob.data | |
bm = bmesh.new() | |
bm.from_mesh(me) | |
self.bm = bm | |
self.islands = BMIslands(bm) | |
def random_color(self, alpha=1): | |
return (uniform(0, 1), uniform(0, 1), uniform(0, 1), alpha) | |
def random_hsv_colors(self, size, sat_limits, val_limits, shuffle=True, alpha=1): | |
rgb_clrs = {} | |
for i in range(size): | |
h, s, v = ( | |
(i*(1/size)), | |
uniform(sat_limits[0], sat_limits[1]), | |
uniform(val_limits[0], val_limits[1])) | |
r, g, b = hsv_to_rgb(h, s, v) | |
rgb_clrs[i] = (r, g, b, alpha) | |
if shuffle: | |
seed = sample(list(rgb_clrs.values()), len(rgb_clrs)) | |
rgb_clrs = {i : seed[i] for i in range(len(seed))} | |
return rgb_clrs | |
def randomize(self, ob): | |
me = ob.data | |
clayers = self.bm.loops.layers.color | |
color_layer = clayers.get(self.layer) or clayers.new(self.layer) | |
clrs = self.random_hsv_colors( | |
len(self.islands), self.satuation, self.lightness, self.shuffle) | |
ami = ob.active_material_index | |
for c, island in enumerate(self.islands): | |
rbga = clrs[c] | |
for f in island.faces: | |
f.material_index = ami | |
for l in f.loops: | |
l[color_layer] = rbga | |
self.bm.to_mesh(me) | |
me.update() | |
me.vertex_colors.active = me.vertex_colors[self.layer] | |
def invoke(self, context, event): | |
ob = context.object | |
self.main(ob) | |
return self.execute(context) | |
def execute(self, context): | |
self.randomize(context.object) | |
return {'FINISHED'} | |
def draw(self, context): | |
layout = self.layout | |
row = layout.row() | |
layout.prop(self, "satuation", text="Saturation (Min Max)") | |
layout.prop(self, "lightness", text="Lightness (Min Max)") | |
layout.separator() | |
layout.prop(self, "shuffle", text="Shuffle Colors") | |
layout.separator() | |
layout.prop(self, "layer") | |
layout.separator() | |
layout.operator(self.__class__.bl_idname, text="Randomize", icon="FILE_REFRESH") | |
def draw_random_island_vertex_color(self, context): | |
layout = self.layout | |
layout.operator( | |
MESH_OT_random_island_vertex_color.bl_idname, | |
icon='RESTRICT_COLOR_ON', | |
text="Random Vertex Colors") | |
def register(): | |
bpy.utils.register_class(MESH_OT_random_island_vertex_color) | |
bpy.types.VIEW3D_MT_paint_vertex.append(draw_random_island_vertex_color) | |
def unregister(): | |
bpy.utils.unregister_class(MESH_OT_random_island_vertex_color) | |
bpy.types.VIEW3D_MT_paint_vertex.remove(draw_random_island_vertex_color) | |
if __name__ == "__main__": | |
register() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment