Cleanup: trailing space
[blender-addons.git] / mesh_tissue / material_tools.py
bloba734abeb18ba175e497b174cada39580c928866c
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # #
20 # (c) Alessandro Zomparelli #
21 # (2020) #
22 # #
23 # http://www.co-de-it.com/ #
24 # #
25 ################################################################################
27 import bpy
28 import numpy as np
30 import colorsys
31 from numpy import *
33 from bpy.types import (
34 Operator,
35 Panel
38 from bpy.props import (
39 BoolProperty,
40 EnumProperty,
41 FloatProperty,
42 IntProperty,
43 StringProperty,
44 FloatVectorProperty,
45 IntVectorProperty
48 from .utils import *
50 class random_materials(Operator):
51 bl_idname = "object.random_materials"
52 bl_label = "Random Materials"
53 bl_description = "Assign random materials to the faces of the mesh"
54 bl_options = {'REGISTER', 'UNDO'}
56 prefix : StringProperty(
57 name="Prefix", default="Random.", description="Name prefix")
59 color_A : FloatVectorProperty(name="Color A",
60 subtype='COLOR_GAMMA',
61 min=0,
62 max=1,
63 default=[0,0,0])
65 color_B : FloatVectorProperty(name="Color B",
66 subtype='COLOR_GAMMA',
67 min=0,
68 max=1,
69 default=[1,1,1])
71 hue : FloatProperty(name="Hue", min=0, max=1, default=0.5)
72 hue_variation : FloatProperty(name="Hue Variation", min=0, max=1, default=0.6)
74 seed : IntProperty(
75 name="Seed", default=0, description="Random seed")
77 count : IntProperty(
78 name="Count", default=3, min=2, description="Count of random materials")
80 generate_materials : BoolProperty(
81 name="Generate Materials", default=False, description="Automatically generates new materials")
83 random_colors : BoolProperty(
84 name="Random Colors", default=True, description="Colors are automatically generated")
86 executed = False
88 @classmethod
89 def poll(cls, context):
90 try: return context.object.type == 'MESH'
91 except: return False
93 def draw(self, context):
94 layout = self.layout
95 col = layout.column(align=True)
96 col.prop(self, "seed")
97 col.prop(self, "generate_materials")
98 if self.generate_materials:
99 col.prop(self, "prefix")
100 col.separator()
101 col.prop(self, "count")
102 #row = col.row(align=True)
103 col.separator()
104 col.label(text='Colors:')
105 col.prop(self, "hue")
106 col.prop(self, "hue_variation")
107 #col.prop(self, "random_colors")
108 if not self.random_colors:
109 col.prop(self, "color_A")
110 col.prop(self, "color_B")
112 def execute(self, context):
113 bpy.ops.object.mode_set(mode='OBJECT')
114 ob = context.active_object
115 if len(ob.material_slots) == 0 and not self.executed:
116 self.generate_materials = True
117 if self.generate_materials:
118 colA = self.color_A
119 colB = self.color_B
120 h1 = (self.hue - self.hue_variation/2)
121 h2 = (self.hue + self.hue_variation/2)
122 count = self.count
123 ob.data.materials.clear()
124 materials = []
125 for i in range(count):
126 mat_name = '{}{:03d}'.format(self.prefix,i)
127 mat = bpy.data.materials.new(mat_name)
128 if self.random_colors:
129 mat.diffuse_color = colorsys.hsv_to_rgb((h1 + (h2-h1)/(count)*i)%1, 1, 1)[:] + (1,)
130 else:
131 mat.diffuse_color = list(colA + (colB - colA)/(count-1)*i) + [1]
132 ob.data.materials.append(mat)
133 else:
134 count = len(ob.material_slots)
135 np.random.seed(seed=self.seed)
136 n_faces = len(ob.data.polygons)
137 if count > 0:
138 rand = list(np.random.randint(count, size=n_faces))
139 ob.data.polygons.foreach_set('material_index',rand)
140 ob.data.update()
141 self.executed = True
142 return {'FINISHED'}
144 class weight_to_materials(Operator):
145 bl_idname = "object.weight_to_materials"
146 bl_label = "Weight to Materials"
147 bl_description = "Assign materials to the faces of the mesh according to the active Vertex Group"
148 bl_options = {'REGISTER', 'UNDO'}
150 prefix : StringProperty(
151 name="Prefix", default="Weight.", description="Name prefix")
153 hue : FloatProperty(name="Hue", min=0, max=1, default=0.5)
154 hue_variation : FloatProperty(name="Hue Variation", min=0, max=1, default=0.3)
156 count : IntProperty(
157 name="Count", default=3, min=2, description="Count of random materials")
159 generate_materials : BoolProperty(
160 name="Generate Materials", default=False, description="Automatically generates new materials")
162 mode : EnumProperty(
163 items=(
164 ('MIN', "Min", "Use the min weight value"),
165 ('MAX', "Max", "Use the max weight value"),
166 ('MEAN', "Mean", "Use the mean weight value")
168 default='MEAN',
169 name="Mode"
172 vg = None
174 @classmethod
175 def poll(cls, context):
176 try: return context.object.type == 'MESH'
177 except: return False
179 def draw(self, context):
180 layout = self.layout
181 col = layout.column(align=True)
182 col.prop(self, "mode")
183 col.prop(self, "generate_materials")
184 if self.generate_materials:
185 col.prop(self, "prefix")
186 col.separator()
187 col.prop(self, "count")
188 #row = col.row(align=True)
189 col.separator()
190 col.label(text='Colors:')
191 col.prop(self, "hue")
192 col.prop(self, "hue_variation")
194 def execute(self, context):
195 ob = context.active_object
196 if self.vg == None:
197 self.vg = ob.vertex_groups.active_index
198 vg = ob.vertex_groups[self.vg]
199 if vg == None:
200 self.report({'ERROR'}, "The selected object doesn't have any Vertex Group")
201 return {'CANCELLED'}
202 weight = get_weight_numpy(vg, len(ob.data.vertices))
203 if self.generate_materials:
204 h1 = (self.hue - self.hue_variation/2)
205 h2 = (self.hue + self.hue_variation/2)
206 count = self.count
207 ob.data.materials.clear()
208 materials = []
209 for i in range(count):
210 mat_name = '{}{:03d}'.format(self.prefix,i)
211 mat = bpy.data.materials.new(mat_name)
212 mat.diffuse_color = colorsys.hsv_to_rgb((h1 + (h2-h1)/(count)*i)%1, 1, 1)[:] + (1,)
213 ob.data.materials.append(mat)
214 else:
215 count = len(ob.material_slots)
217 faces_weight = []
218 for p in ob.data.polygons:
219 verts_id = np.array([v for v in p.vertices])
220 face_weight = weight[verts_id]
221 if self.mode == 'MIN': w = face_weight.min()
222 if self.mode == 'MAX': w = face_weight.max()
223 if self.mode == 'MEAN': w = face_weight.mean()
224 faces_weight.append(w)
225 faces_weight = np.array(faces_weight)
226 faces_weight = faces_weight * count
227 faces_weight.astype('int')
228 ob.data.polygons.foreach_set('material_index',list(faces_weight))
229 ob.data.update()
230 bpy.ops.object.mode_set(mode='OBJECT')
231 return {'FINISHED'}