1 # SPDX-FileCopyrightText: 2019-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # Repeats extrusion + rotation + scale for one or more faces
6 # Original code by liero
7 # Update by Jimmy Hazevoet 03/2017 for Blender 2.79
8 # normal rotation, probability, scaled offset, object coords, initial and per step noise
12 "name": "MExtrude Plus1",
13 "author": "liero, Jimmy Hazevoet",
15 "blender": (2, 77, 0),
16 "location": "View3D > Tool Shelf",
17 "description": "Repeat extrusions from faces to create organic shapes",
27 from bpy
.types
import Operator
28 from random
import gauss
29 from math
import radians
30 from mathutils
import (
33 from bpy
.props
import (
41 return Vector((self
.offx
, self
.offy
, self
.offz
))
45 random
.seed(self
.ran
+ r
)
46 return self
.off
* (1 + gauss(0, self
.var1
/ 3))
50 return Euler((radians(self
.nrotx
) * n
[0],
51 radians(self
.nroty
) * n
[1],
52 radians(self
.nrotz
) * n
[2]), 'XYZ')
56 random
.seed(self
.ran
+ r
)
57 return Euler((radians(self
.rotx
) + gauss(0, self
.var2
/ 3),
58 radians(self
.roty
) + gauss(0, self
.var2
/ 3),
59 radians(self
.rotz
) + gauss(0, self
.var2
/ 3)), 'XYZ')
63 random
.seed(self
.ran
+ r
)
64 return self
.sca
* (1 + gauss(0, self
.var3
/ 3))
67 class MExtrude(Operator
):
68 bl_idname
= "object.mextrude"
69 bl_label
= "Multi Extrude"
70 bl_description
= ("Extrude selected Faces with Rotation,\n"
71 "Scaling, Variation, Randomization")
72 bl_options
= {"REGISTER", "UNDO", "PRESET"}
76 soft_min
=0.001, soft_max
=10,
79 description
="Translation"
83 soft_min
=-10.0, soft_max
=10.0,
84 min=-100.0, max=100.0,
86 description
="Global Translation X"
90 soft_min
=-10.0, soft_max
=10.0,
91 min=-100.0, max=100.0,
93 description
="Global Translation Y"
97 soft_min
=-10.0, soft_max
=10.0,
98 min=-100.0, max=100.0,
100 description
="Global Translation Z"
105 soft_min
=-30, soft_max
=30,
107 description
="X Rotation"
115 description
="Y Rotation"
120 soft_min
=-30, soft_max
=30,
122 description
="Z Rotation"
124 nrotx
: FloatProperty(
127 soft_min
=-30, soft_max
=30,
129 description
="Normal X Rotation"
131 nroty
: FloatProperty(
134 soft_min
=-30, soft_max
=30,
136 description
="Normal Y Rotation"
138 nrotz
: FloatProperty(
141 soft_min
=-30, soft_max
=30,
143 description
="Normal Z Rotation"
148 soft_min
=0.5, soft_max
=1.5,
150 description
="Scaling of the selected faces after extrusion"
153 name
="Offset Var", min=-10, max=10,
154 soft_min
=-1, soft_max
=1,
156 description
="Offset variation"
161 soft_min
=-1, soft_max
=1,
163 description
="Rotation variation"
168 soft_min
=-1, soft_max
=1,
170 description
="Scaling noise"
176 description
="Probability, chance of extruding a face"
183 description
="Repetitions"
189 description
="Seed to feed random values"
192 name
="Polygon coordinates",
194 description
="Polygon coordinates, Object coordinates"
197 name
="Proportional offset",
199 description
="Scale * Offset"
202 name
="Per step rotation noise",
204 description
="Per step rotation noise, Initial rotation noise"
207 name
="Per step scale noise",
209 description
="Per step scale noise, Initial scale noise"
213 def poll(cls
, context
):
215 return (obj
and obj
.type == 'MESH')
217 def draw(self
, context
):
219 col
= layout
.column(align
=True)
220 col
.label(text
="Transformations:")
221 col
.prop(self
, "off", slider
=True)
222 col
.prop(self
, "offx", slider
=True)
223 col
.prop(self
, "offy", slider
=True)
224 col
.prop(self
, "offz", slider
=True)
226 col
= layout
.column(align
=True)
227 col
.prop(self
, "rotx", slider
=True)
228 col
.prop(self
, "roty", slider
=True)
229 col
.prop(self
, "rotz", slider
=True)
230 col
.prop(self
, "nrotx", slider
=True)
231 col
.prop(self
, "nroty", slider
=True)
232 col
.prop(self
, "nrotz", slider
=True)
233 col
= layout
.column(align
=True)
234 col
.prop(self
, "sca", slider
=True)
236 col
= layout
.column(align
=True)
237 col
.label(text
="Variation settings:")
238 col
.prop(self
, "var1", slider
=True)
239 col
.prop(self
, "var2", slider
=True)
240 col
.prop(self
, "var3", slider
=True)
241 col
.prop(self
, "var4", slider
=True)
242 col
.prop(self
, "ran")
243 col
= layout
.column(align
=False)
244 col
.prop(self
, 'num')
246 col
= layout
.column(align
=True)
247 col
.label(text
="Options:")
248 col
.prop(self
, "opt1")
249 col
.prop(self
, "opt2")
250 col
.prop(self
, "opt3")
251 col
.prop(self
, "opt4")
253 def execute(self
, context
):
254 obj
= bpy
.context
.object
256 bpy
.context
.tool_settings
.mesh_select_mode
= [False, False, True]
257 origin
= Vector([0.0, 0.0, 0.0])
260 bpy
.ops
.object.mode_set()
262 bm
.from_mesh(obj
.data
)
263 sel
= [f
for f
in bm
.faces
if f
.select
]
268 for i
, of
in enumerate(sel
):
269 nro
= nrot(self
, of
.normal
)
274 # initial rotation noise
275 if self
.opt3
is False:
277 # initial scale noise
278 if self
.opt4
is False:
282 for r
in range(self
.num
):
283 # random probability % for extrusions
284 if self
.var4
> int(random
.random() * 100):
287 no
= nf
.normal
.copy()
289 # face/obj coördinates
290 if self
.opt1
is True:
291 ce
= nf
.calc_center_bounds()
295 # per step rotation noise
296 if self
.opt3
is True:
297 rot
= vrot(self
, i
+ r
)
298 # per step scale noise
299 if self
.opt4
is True:
300 s
= vsca(self
, i
+ r
)
302 # proportional, scale * offset
303 if self
.opt2
is True:
310 v
.co
+= ce
+ loc
+ no
* off
311 v
.co
= v
.co
.lerp(ce
, 1 - s
)
313 # extrude code from TrumanBlending
314 for a
, b
in zip(of
.loops
, nf
.loops
):
315 sf
= bm
.faces
.new((a
.vert
, a
.link_loop_next
.vert
,
316 b
.link_loop_next
.vert
, b
.vert
))
337 # restore user settings
338 bpy
.ops
.object.mode_set(mode
=om
)
341 self
.report({"WARNING"},
342 "No suitable Face selection found. Operation cancelled")
349 bpy
.utils
.register_module(__name__
)
353 bpy
.utils
.unregister_module(__name__
)
356 if __name__
== '__main__':