def adjust_hsv(mesh, vcol, h_offset, s_offset, v_offset, colorize): if mesh.use_paint_mask: selected_faces = [face for face in mesh.polygons if face.select] for face in selected_faces: for loop_index in face.loop_indices: c = Color(vcol.data[loop_index].color[:3]) if colorize: c.h = fmod(0.5 + h_offset, 1.0) else: c.h = fmod(1.0 + c.h + h_offset, 1.0) c.s = max(0.0, min(c.s + s_offset, 1.0)) c.v = max(0.0, min(c.v + v_offset, 1.0)) new_color = vcol.data[loop_index].color new_color[:3] = c vcol.data[loop_index].color = new_color else: vertex_mask = True if mesh.use_paint_mask_vertex else False verts = mesh.vertices for loop_index, loop in enumerate(mesh.loops): if not vertex_mask or verts[loop.vertex_index].select: c = Color(vcol.data[loop_index].color[:3]) if colorize: c.h = fmod(0.5 + h_offset, 1.0) else: c.h = fmod(1.0 + c.h + h_offset, 1.0) c.s = max(0.0, min(c.s + s_offset, 1.0)) c.v = max(0.0, min(c.v + v_offset, 1.0)) new_color = vcol.data[loop_index].color new_color[:3] = c vcol.data[loop_index].color = new_color mesh.update()
def transfer_weight_to_vertex_color(self, obj): col = Color() col.r, col.g, col.b = 1, 1, 1 col.h, col.s, col.v = 0, 1, 1 for poly in obj.data.polygons: for loop in poly.loop_indices: weight = 0 vertindex = obj.data.loops[loop].vertex_index try: weight = obj.vertex_groups.active.weight(vertindex) if self.colored: col.h, col.s, col.v = 0.6666 * weight, 1, 1 else: col.r = col.g = col.b = weight except: if self.colored: col.r, col.g, col.b = 1, 1, 1 col.h, col.s, col.v = 0.666, 1, 1 else: col.h, col.s, col.v = 0, 1, 1 col.r, col.g, col.b = 0, 0, 0 obj.data.vertex_colors.active.data[loop].color = (col.b, col.g, col.r, 1)
def hsv_to_rgb(input, val, i_sub=-1): c = Color(input.default_value[:3]) if i_sub == 0: c.h = val elif i_sub == 1: c.s = val elif i_sub == 2: c.v = val elif i_sub < 0: c.hsv = val return [*c[:], 1.0] # Return RGB values
def paintVerts(self, context, start_point, end_point, start_color, end_color, circular_gradient=False, use_hue_blend=False): region = context.region rv3d = context.region_data obj = context.active_object mesh = obj.data # Create a new bmesh to work with bm = bmesh.new() bm.from_mesh(mesh) bm.verts.ensure_lookup_table() # List of structures containing 3d vertex and project 2d position of vertex vertex_data = None # Will contain vert, and vert coordinates in 2d view space if mesh.use_paint_mask_vertex: # Face masking not currently supported vertex_data = [(v, view3d_utils.location_3d_to_region_2d( region, rv3d, obj.matrix_world @ v.co)) for v in bm.verts if v.select] else: vertex_data = [(v, view3d_utils.location_3d_to_region_2d( region, rv3d, obj.matrix_world @ v.co)) for v in bm.verts] # Vertex transformation math down_vector = Vector((0, -1, 0)) direction_vector = Vector( (end_point.x - start_point.x, end_point.y - start_point.y, 0)).normalized() rotation = direction_vector.rotation_difference(down_vector) translation_matrix = Matrix.Translation( Vector((-start_point.x, -start_point.y, 0))) inverse_translation_matrix = translation_matrix.inverted() rotation_matrix = rotation.to_matrix().to_4x4() combinedMat = inverse_translation_matrix @ rotation_matrix @ translation_matrix transStart = combinedMat @ start_point.to_4d( ) # Transform drawn line : rotate it to align to horizontal line transEnd = combinedMat @ end_point.to_4d() minY = transStart.y maxY = transEnd.y heightTrans = maxY - minY # Get the height of transformed vector transVector = transEnd - transStart transLen = transVector.length # Calculate hue, saturation and value shift for blending if use_hue_blend: start_color = Color(start_color[:3]) end_color = Color(end_color[:3]) c1_hue = start_color.h c2_hue = end_color.h hue_separation = c2_hue - c1_hue if hue_separation > 0.5: hue_separation = hue_separation - 1 elif hue_separation < -0.5: hue_separation = hue_separation + 1 c1_sat = start_color.s sat_separation = end_color.s - c1_sat c1_val = start_color.v val_separation = end_color.v - c1_val color_layer = bm.loops.layers.color.active for data in vertex_data: vertex = data[0] vertCo4d = Vector((data[1].x, data[1].y, 0)) transVec = combinedMat @ vertCo4d t = 0 if circular_gradient: curVector = transVec.to_4d() - transStart curLen = curVector.length t = abs(max(min(curLen / transLen, 1), 0)) else: t = abs(max(min((transVec.y - minY) / heightTrans, 1), 0)) color = Color((1, 0, 0)) if use_hue_blend: # Hue wraps, and fmod doesn't work with negative values color.h = fmod(1.0 + c1_hue + hue_separation * t, 1.0) color.s = c1_sat + sat_separation * t color.v = c1_val + val_separation * t else: color.r = start_color[0] + (end_color[0] - start_color[0]) * t color.g = start_color[1] + (end_color[1] - start_color[1]) * t color.b = start_color[2] + (end_color[2] - start_color[2]) * t if mesh.use_paint_mask: # Masking by face face_loops = [ loop for loop in vertex.link_loops if loop.face.select ] # Get only loops that belong to selected faces else: # Masking by verts or no masking at all face_loops = [loop for loop in vertex.link_loops ] # Get remaining vert loops for loop in face_loops: new_color = loop[color_layer] new_color[:3] = color loop[color_layer] = new_color bm.to_mesh(mesh) bm.free() bpy.ops.object.mode_set(mode='VERTEX_PAINT')
def execute(self, context): mesh = context.active_object.data random.seed(self.random_seed) bpy.ops.object.mode_set(mode='EDIT', toggle=False) bm = bmesh.from_edit_mesh(mesh) bm.faces.ensure_lookup_table() color_layer = bm.loops.layers.color.active # Find all islands in the mesh mesh_islands = [] selected_faces = ([f for f in bm.faces if f.select]) faces = selected_faces if mesh.use_paint_mask or mesh.use_paint_mask_vertex else bm.faces bpy.ops.mesh.select_all(action="DESELECT") while len(faces) > 0: # Select linked faces to find island faces[0].select_set(True) bpy.ops.mesh.select_linked() mesh_islands.append([f for f in faces if f.select]) # Hide the island and update faces bpy.ops.mesh.hide(unselected=False) faces = [f for f in faces if not f.hide] bpy.ops.mesh.reveal() island_colors = {} # Island face count : Random color pairs # Used for setting hue with order based color assignment separationDiff = 1.0 if len( mesh_islands) == 0 else 1.0 / len(mesh_islands) # If we are in isolate mode, this is used to force greyscale isolate = get_isolated_channel_ids( context.active_object.data.vertex_colors.active) for index, island in enumerate(mesh_islands): color = Color((1, 0, 0)) # (0, 1, 1) HSV # Determine color based on settings if self.merge_similar: face_count = len(island) if face_count in island_colors.keys(): color = island_colors[face_count] else: if isolate is not None: v = random.random() color = Color((v, v, v)) island_colors[face_count] = color else: color.h = random.random( ) if self.randomize_hue else self.base_hue color.s = random.random( ) if self.randomize_saturation else self.base_saturation color.v = random.random( ) if self.randomize_value else self.base_value island_colors[face_count] = color else: if isolate is not None: v = index * separationDiff if self.order_based else random.random( ) color = Color((v, v, v)) else: if self.order_based: color.h = index * separationDiff if self.randomize_hue else self.base_hue color.s = index * separationDiff if self.randomize_saturation else self.base_saturation color.v = index * separationDiff if self.randomize_value else self.base_value else: color.h = random.random( ) if self.randomize_hue else self.base_hue color.s = random.random( ) if self.randomize_saturation else self.base_saturation color.v = random.random( ) if self.randomize_value else self.base_value # Set island face colors for face in island: for loop in face.loops: new_color = loop[color_layer] new_color[:3] = color loop[color_layer] = new_color # Restore selection for f in selected_faces: f.select = True bm.free() bpy.ops.object.mode_set(mode='VERTEX_PAINT', toggle=False) return {'FINISHED'}