Update scripts to account for removal of the context override to bpy.ops
[blender-addons.git] / mesh_tissue / material_tools.py
blobb41568c40d3a2e19077949987e5facd53dfbc356
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # #
4 # (c) Alessandro Zomparelli #
5 # (2020) #
6 # #
7 # http://www.co-de-it.com/ #
8 # #
9 ################################################################################
11 import bpy
12 import numpy as np
14 import colorsys
15 from numpy import *
17 from bpy.types import (
18 Operator,
19 Panel
22 from bpy.props import (
23 BoolProperty,
24 EnumProperty,
25 FloatProperty,
26 IntProperty,
27 StringProperty,
28 FloatVectorProperty,
29 IntVectorProperty
32 from .utils import *
34 class random_materials(Operator):
35 bl_idname = "object.random_materials"
36 bl_label = "Random Materials"
37 bl_description = "Assign random materials to the faces of the mesh"
38 bl_options = {'REGISTER', 'UNDO'}
40 prefix : StringProperty(
41 name="Prefix", default="Random.", description="Name prefix")
43 color_A : FloatVectorProperty(name="Color A",
44 subtype='COLOR_GAMMA',
45 min=0,
46 max=1,
47 default=[0,0,0])
49 color_B : FloatVectorProperty(name="Color B",
50 subtype='COLOR_GAMMA',
51 min=0,
52 max=1,
53 default=[1,1,1])
55 hue : FloatProperty(name="Hue", min=0, max=1, default=0.5)
56 hue_variation : FloatProperty(name="Hue Variation", min=0, max=1, default=0.6)
58 seed : IntProperty(
59 name="Seed", default=0, description="Random seed")
61 count : IntProperty(
62 name="Count", default=3, min=2, description="Count of random materials")
64 generate_materials : BoolProperty(
65 name="Generate Materials", default=False, description="Automatically generates new materials")
67 random_colors : BoolProperty(
68 name="Random Colors", default=True, description="Colors are automatically generated")
70 executed = False
72 @classmethod
73 def poll(cls, context):
74 try: return context.object.type == 'MESH'
75 except: return False
77 def draw(self, context):
78 layout = self.layout
79 col = layout.column(align=True)
80 col.prop(self, "seed")
81 col.prop(self, "generate_materials")
82 if self.generate_materials:
83 col.prop(self, "prefix")
84 col.separator()
85 col.prop(self, "count")
86 #row = col.row(align=True)
87 col.separator()
88 col.label(text='Colors:')
89 col.prop(self, "hue")
90 col.prop(self, "hue_variation")
91 #col.prop(self, "random_colors")
92 if not self.random_colors:
93 col.prop(self, "color_A")
94 col.prop(self, "color_B")
96 def execute(self, context):
97 bpy.ops.object.mode_set(mode='OBJECT')
98 ob = context.active_object
99 if len(ob.material_slots) == 0 and not self.executed:
100 self.generate_materials = True
101 if self.generate_materials:
102 colA = self.color_A
103 colB = self.color_B
104 h1 = (self.hue - self.hue_variation/2)
105 h2 = (self.hue + self.hue_variation/2)
106 count = self.count
107 ob.data.materials.clear()
108 materials = []
109 for i in range(count):
110 mat_name = '{}{:03d}'.format(self.prefix,i)
111 mat = bpy.data.materials.new(mat_name)
112 if self.random_colors:
113 mat.diffuse_color = colorsys.hsv_to_rgb((h1 + (h2-h1)/(count)*i)%1, 1, 1)[:] + (1,)
114 else:
115 mat.diffuse_color = list(colA + (colB - colA)/(count-1)*i) + [1]
116 ob.data.materials.append(mat)
117 else:
118 count = len(ob.material_slots)
119 np.random.seed(seed=self.seed)
120 n_faces = len(ob.data.polygons)
121 if count > 0:
122 rand = list(np.random.randint(count, size=n_faces))
123 ob.data.polygons.foreach_set('material_index',rand)
124 ob.data.update()
125 self.executed = True
126 return {'FINISHED'}
128 class weight_to_materials(Operator):
129 bl_idname = "object.weight_to_materials"
130 bl_label = "Weight to Materials"
131 bl_description = "Assign materials to the faces of the mesh according to the active Vertex Group"
132 bl_options = {'REGISTER', 'UNDO'}
134 prefix : StringProperty(
135 name="Prefix", default="Weight.", description="Name prefix")
137 hue : FloatProperty(name="Hue", min=0, max=1, default=0.5)
138 hue_variation : FloatProperty(name="Hue Variation", min=0, max=1, default=0.3)
140 count : IntProperty(
141 name="Count", default=3, min=2, description="Count of random materials")
143 generate_materials : BoolProperty(
144 name="Generate Materials", default=False, description="Automatically generates new materials")
146 mode : EnumProperty(
147 items=(
148 ('MIN', "Min", "Use the min weight value"),
149 ('MAX', "Max", "Use the max weight value"),
150 ('MEAN', "Mean", "Use the mean weight value")
152 default='MEAN',
153 name="Mode"
156 vg = None
158 @classmethod
159 def poll(cls, context):
160 try: return context.object.type == 'MESH'
161 except: return False
163 def draw(self, context):
164 layout = self.layout
165 col = layout.column(align=True)
166 col.prop(self, "mode")
167 col.prop(self, "generate_materials")
168 if self.generate_materials:
169 col.prop(self, "prefix")
170 col.separator()
171 col.prop(self, "count")
172 #row = col.row(align=True)
173 col.separator()
174 col.label(text='Colors:')
175 col.prop(self, "hue")
176 col.prop(self, "hue_variation")
178 def execute(self, context):
179 ob = context.active_object
180 if self.vg == None:
181 self.vg = ob.vertex_groups.active_index
182 vg = ob.vertex_groups[self.vg]
183 if vg == None:
184 self.report({'ERROR'}, "The selected object doesn't have any Vertex Group")
185 return {'CANCELLED'}
186 weight = get_weight_numpy(vg, len(ob.data.vertices))
187 if self.generate_materials:
188 h1 = (self.hue - self.hue_variation/2)
189 h2 = (self.hue + self.hue_variation/2)
190 count = self.count
191 ob.data.materials.clear()
192 materials = []
193 for i in range(count):
194 mat_name = '{}{:03d}'.format(self.prefix,i)
195 mat = bpy.data.materials.new(mat_name)
196 mat.diffuse_color = colorsys.hsv_to_rgb((h1 + (h2-h1)/(count)*i)%1, 1, 1)[:] + (1,)
197 ob.data.materials.append(mat)
198 else:
199 count = len(ob.material_slots)
201 faces_weight = []
202 for p in ob.data.polygons:
203 verts_id = np.array([v for v in p.vertices])
204 face_weight = weight[verts_id]
205 if self.mode == 'MIN': w = face_weight.min()
206 if self.mode == 'MAX': w = face_weight.max()
207 if self.mode == 'MEAN': w = face_weight.mean()
208 faces_weight.append(w)
209 faces_weight = np.array(faces_weight)
210 faces_weight = faces_weight * count
211 faces_weight.astype('int')
212 ob.data.polygons.foreach_set('material_index',list(faces_weight))
213 ob.data.update()
214 bpy.ops.object.mode_set(mode='OBJECT')
215 return {'FINISHED'}