1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # Repeats extrusion + rotation + scale for one or more faces
4 # Original code by liero
5 # Update by Jimmy Hazevoet 03/2017 for Blender 2.79
6 # normal rotation, probability, scaled offset, object coords, initial and per step noise
10 "name": "MExtrude Plus1",
11 "author": "liero, Jimmy Hazevoet",
13 "blender": (2, 77, 0),
14 "location": "View3D > Tool Shelf",
15 "description": "Repeat extrusions from faces to create organic shapes",
25 from bpy
.types
import Operator
26 from random
import gauss
27 from math
import radians
28 from mathutils
import (
31 from bpy
.props
import (
39 return Vector((self
.offx
, self
.offy
, self
.offz
))
43 random
.seed(self
.ran
+ r
)
44 return self
.off
* (1 + gauss(0, self
.var1
/ 3))
48 return Euler((radians(self
.nrotx
) * n
[0],
49 radians(self
.nroty
) * n
[1],
50 radians(self
.nrotz
) * n
[2]), 'XYZ')
54 random
.seed(self
.ran
+ r
)
55 return Euler((radians(self
.rotx
) + gauss(0, self
.var2
/ 3),
56 radians(self
.roty
) + gauss(0, self
.var2
/ 3),
57 radians(self
.rotz
) + gauss(0, self
.var2
/ 3)), 'XYZ')
61 random
.seed(self
.ran
+ r
)
62 return self
.sca
* (1 + gauss(0, self
.var3
/ 3))
65 class MExtrude(Operator
):
66 bl_idname
= "object.mextrude"
67 bl_label
= "Multi Extrude"
68 bl_description
= ("Extrude selected Faces with Rotation,\n"
69 "Scaling, Variation, Randomization")
70 bl_options
= {"REGISTER", "UNDO", "PRESET"}
74 soft_min
=0.001, soft_max
=10,
77 description
="Translation"
81 soft_min
=-10.0, soft_max
=10.0,
82 min=-100.0, max=100.0,
84 description
="Global Translation X"
88 soft_min
=-10.0, soft_max
=10.0,
89 min=-100.0, max=100.0,
91 description
="Global Translation Y"
95 soft_min
=-10.0, soft_max
=10.0,
96 min=-100.0, max=100.0,
98 description
="Global Translation Z"
103 soft_min
=-30, soft_max
=30,
105 description
="X Rotation"
113 description
="Y Rotation"
118 soft_min
=-30, soft_max
=30,
120 description
="Z Rotation"
122 nrotx
: FloatProperty(
125 soft_min
=-30, soft_max
=30,
127 description
="Normal X Rotation"
129 nroty
: FloatProperty(
132 soft_min
=-30, soft_max
=30,
134 description
="Normal Y Rotation"
136 nrotz
: FloatProperty(
139 soft_min
=-30, soft_max
=30,
141 description
="Normal Z Rotation"
146 soft_min
=0.5, soft_max
=1.5,
148 description
="Scaling of the selected faces after extrusion"
151 name
="Offset Var", min=-10, max=10,
152 soft_min
=-1, soft_max
=1,
154 description
="Offset variation"
159 soft_min
=-1, soft_max
=1,
161 description
="Rotation variation"
166 soft_min
=-1, soft_max
=1,
168 description
="Scaling noise"
174 description
="Probability, chance of extruding a face"
181 description
="Repetitions"
187 description
="Seed to feed random values"
190 name
="Polygon coordinates",
192 description
="Polygon coordinates, Object coordinates"
195 name
="Proportional offset",
197 description
="Scale * Offset"
200 name
="Per step rotation noise",
202 description
="Per step rotation noise, Initial rotation noise"
205 name
="Per step scale noise",
207 description
="Per step scale noise, Initial scale noise"
211 def poll(cls
, context
):
213 return (obj
and obj
.type == 'MESH')
215 def draw(self
, context
):
217 col
= layout
.column(align
=True)
218 col
.label(text
="Transformations:")
219 col
.prop(self
, "off", slider
=True)
220 col
.prop(self
, "offx", slider
=True)
221 col
.prop(self
, "offy", slider
=True)
222 col
.prop(self
, "offz", slider
=True)
224 col
= layout
.column(align
=True)
225 col
.prop(self
, "rotx", slider
=True)
226 col
.prop(self
, "roty", slider
=True)
227 col
.prop(self
, "rotz", slider
=True)
228 col
.prop(self
, "nrotx", slider
=True)
229 col
.prop(self
, "nroty", slider
=True)
230 col
.prop(self
, "nrotz", slider
=True)
231 col
= layout
.column(align
=True)
232 col
.prop(self
, "sca", slider
=True)
234 col
= layout
.column(align
=True)
235 col
.label(text
="Variation settings:")
236 col
.prop(self
, "var1", slider
=True)
237 col
.prop(self
, "var2", slider
=True)
238 col
.prop(self
, "var3", slider
=True)
239 col
.prop(self
, "var4", slider
=True)
240 col
.prop(self
, "ran")
241 col
= layout
.column(align
=False)
242 col
.prop(self
, 'num')
244 col
= layout
.column(align
=True)
245 col
.label(text
="Options:")
246 col
.prop(self
, "opt1")
247 col
.prop(self
, "opt2")
248 col
.prop(self
, "opt3")
249 col
.prop(self
, "opt4")
251 def execute(self
, context
):
252 obj
= bpy
.context
.object
254 bpy
.context
.tool_settings
.mesh_select_mode
= [False, False, True]
255 origin
= Vector([0.0, 0.0, 0.0])
258 bpy
.ops
.object.mode_set()
260 bm
.from_mesh(obj
.data
)
261 sel
= [f
for f
in bm
.faces
if f
.select
]
266 for i
, of
in enumerate(sel
):
267 nro
= nrot(self
, of
.normal
)
272 # initial rotation noise
273 if self
.opt3
is False:
275 # initial scale noise
276 if self
.opt4
is False:
280 for r
in range(self
.num
):
281 # random probability % for extrusions
282 if self
.var4
> int(random
.random() * 100):
285 no
= nf
.normal
.copy()
287 # face/obj coördinates
288 if self
.opt1
is True:
289 ce
= nf
.calc_center_bounds()
293 # per step rotation noise
294 if self
.opt3
is True:
295 rot
= vrot(self
, i
+ r
)
296 # per step scale noise
297 if self
.opt4
is True:
298 s
= vsca(self
, i
+ r
)
300 # proportional, scale * offset
301 if self
.opt2
is True:
308 v
.co
+= ce
+ loc
+ no
* off
309 v
.co
= v
.co
.lerp(ce
, 1 - s
)
311 # extrude code from TrumanBlending
312 for a
, b
in zip(of
.loops
, nf
.loops
):
313 sf
= bm
.faces
.new((a
.vert
, a
.link_loop_next
.vert
,
314 b
.link_loop_next
.vert
, b
.vert
))
335 # restore user settings
336 bpy
.ops
.object.mode_set(mode
=om
)
339 self
.report({"WARNING"},
340 "No suitable Face selection found. Operation cancelled")
347 bpy
.utils
.register_module(__name__
)
351 bpy
.utils
.unregister_module(__name__
)
354 if __name__
== '__main__':