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