1 # GPL # "author": "Phil Cote, cotejrp1, (http://www.blenderaddons.com)"
5 from bpy
.props
import (
12 from mathutils
import (
16 from bpy_extras
import object_utils
19 def create_step(width
, base_level
, step_height
, num_sides
):
25 quat_angles
= [(cur_side
/ num_sides
) * PI2
26 for cur_side
in range(num_sides
)]
28 quaternions
= [Quaternion(axis
, quat_angle
)
29 for quat_angle
in quat_angles
]
31 init_vectors
= [Vector([rad
, 0, base_level
])] * len(quaternions
)
33 quat_vector_pairs
= list(zip(quaternions
, init_vectors
))
34 vectors
= [quaternion
@ vec
for quaternion
, vec
in quat_vector_pairs
]
35 bottom_list
= [(vec
.x
, vec
.y
, vec
.z
) for vec
in vectors
]
36 top_list
= [(vec
.x
, vec
.y
, vec
.z
+ step_height
) for vec
in vectors
]
37 full_list
= bottom_list
+ top_list
44 split the blocks up. Credit to oremj for this one.
45 http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python
48 returned_list
= [l
[i
: i
+ n
] for i
in range(0, len(l
), n
)]
52 def get_connector_pairs(lst
, n_sides
):
53 # chop off the verts that get used for the base and top
56 lst
= split_list(lst
, n_sides
)
60 def pyramid_mesh(self
, context
):
64 cur_width
= self
.width
66 for i
in range(self
.num_steps
):
67 verts_loc
= create_step(cur_width
, height_offset
, self
.height
,
69 height_offset
+= self
.height
70 cur_width
-= self
.reduce_by
71 all_verts
.extend(verts_loc
)
73 mesh
= bpy
.data
.meshes
.new("Pyramid")
76 for v_co
in all_verts
:
79 def add_faces(n
, block_vert_sets
):
80 for bvs
in block_vert_sets
:
81 for i
in range(self
.num_sides
- 1):
82 bm
.faces
.new([bvs
[i
], bvs
[i
+ n
], bvs
[i
+ n
+ 1], bvs
[i
+ 1]])
83 bm
.faces
.new([bvs
[n
- 1], bvs
[(n
* 2) - 1], bvs
[n
], bvs
[0]])
85 # get the base and cap faces done.
86 bm
.faces
.new(bm
.verts
[0:self
.num_sides
])
87 bm
.faces
.new(reversed(bm
.verts
[-self
.num_sides
:])) # otherwise normal faces intern... T44619.
90 block_vert_sets
= split_list(bm
.verts
, self
.num_sides
)
91 add_faces(self
.num_sides
, block_vert_sets
)
93 # connector faces between faces and faces of the block above it.
94 connector_pairs
= get_connector_pairs(bm
.verts
, self
.num_sides
)
95 add_faces(self
.num_sides
, connector_pairs
)
103 class AddPyramid(bpy
.types
.Operator
, object_utils
.AddObjectHelper
):
104 bl_idname
= "mesh.primitive_steppyramid_add"
106 bl_description
= "Construct a step pyramid mesh"
107 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
109 Pyramid
: BoolProperty(name
= "Pyramid",
111 description
= "Pyramid")
112 change
: BoolProperty(name
= "Change",
114 description
= "change Pyramid")
116 num_sides
: IntProperty(
118 description
="How many sides each step will have",
122 num_steps
: IntProperty(
123 name
="Number of Steps",
124 description
="How many steps for the overall pyramid",
128 width
: FloatProperty(
129 name
="Initial Width",
130 description
="Initial base step width",
134 height
: FloatProperty(
136 description
="How tall each step will be",
140 reduce_by
: FloatProperty(
141 name
="Reduce Step By",
142 description
="How much to reduce each succeeding step by",
147 def draw(self
, context
):
150 layout
.prop(self
, 'num_sides', expand
=True)
151 layout
.prop(self
, 'num_steps', expand
=True)
152 layout
.prop(self
, 'width', expand
=True)
153 layout
.prop(self
, 'height', expand
=True)
154 layout
.prop(self
, 'reduce_by', expand
=True)
156 if self
.change
== False:
157 col
= layout
.column(align
=True)
158 col
.prop(self
, 'align', expand
=True)
159 col
= layout
.column(align
=True)
160 col
.prop(self
, 'location', expand
=True)
161 col
= layout
.column(align
=True)
162 col
.prop(self
, 'rotation', expand
=True)
164 def execute(self
, context
):
165 # turn off 'Enter Edit Mode'
166 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
167 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
169 if bpy
.context
.mode
== "OBJECT":
170 if context
.selected_objects
!= [] and context
.active_object
and \
171 ('Pyramid' in context
.active_object
.data
.keys()) and (self
.change
== True):
172 obj
= context
.active_object
174 oldmeshname
= obj
.data
.name
175 obj
.data
= pyramid_mesh(self
, context
)
176 for material
in oldmesh
.materials
:
177 obj
.data
.materials
.append(material
)
178 bpy
.data
.meshes
.remove(oldmesh
)
179 obj
.data
.name
= oldmeshname
181 mesh
= pyramid_mesh(self
, context
)
182 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
184 obj
.data
["Pyramid"] = True
185 obj
.data
["change"] = False
186 for prm
in PyramidParameters():
187 obj
.data
[prm
] = getattr(self
, prm
)
189 if bpy
.context
.mode
== "EDIT_MESH":
190 active_object
= context
.active_object
191 name_active_object
= active_object
.name
192 bpy
.ops
.object.mode_set(mode
='OBJECT')
193 mesh
= pyramid_mesh(self
, context
)
194 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
196 active_object
.select_set(True)
197 bpy
.ops
.object.join()
198 context
.active_object
.name
= name_active_object
199 bpy
.ops
.object.mode_set(mode
='EDIT')
201 if use_enter_edit_mode
:
202 bpy
.ops
.object.mode_set(mode
= 'EDIT')
204 # restore pre operator state
205 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
209 def PyramidParameters():
210 PyramidParameters
= [
217 return PyramidParameters