-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathadd_star_with_modifier.py
More file actions
148 lines (116 loc) · 4.57 KB
/
Copy pathadd_star_with_modifier.py
File metadata and controls
148 lines (116 loc) · 4.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# SPDX-FileCopyrightText: © 2016 Michel Anders (varkenvarken) & contributors
#
# SPDX-License-Identifier: GPL-2.0-or-later
bl_info = {
"name": "Star",
"author": "Your Name",
"version": (0, 0, 4),
"blender": (5, 0, 0),
"location": "Object > Add",
"description": "Add a star shaped mesh to the scene",
"category": "Object",
}
import bpy
from bpy.types import Operator
from bpy.props import IntProperty, FloatProperty
# help function to check that that the outer radius is
# always larger than the inner radius.
# Note that the comparisons are strict, i.e. do NOT
# check for equality to prevent infinite recursion!
def update_outer_radius(self, context):
"""make sure outer radius > inner radius"""
if self.inner_radius > self.outer_radius:
self.outer_radius = self.inner_radius
def update_inner_radius(self, context):
"""make sure inner radius <= outer radius"""
if self.outer_radius < self.inner_radius:
self.inner_radius = self.outer_radius
class OBJECT_OT_add_star(Operator):
bl_idname = "object.add_star"
bl_label = "Add star"
bl_description = "Add a star shaped mesh to the scene"
bl_options = {"REGISTER", "UNDO"}
points: IntProperty(
name="Points",
description="Number of points on the star",
default=5,
min=3,
soft_max=20,
)
inner_radius: FloatProperty(
name="Inner radius",
description="Distance from center to indented vertices",
default=1.0,
min=0.001,
update=update_outer_radius,
)
outer_radius: FloatProperty(
name="Outer radius",
description="Distance from center to point tips",
default=1.5,
min=0.0001,
update=update_inner_radius,
)
def set_vertex_selection_mode(self):
"""Save current selection mode and switch to vertex selection mode."""
self.old_selection_modes = [
mode for mode in bpy.context.scene.tool_settings.mesh_select_mode
]
bpy.context.scene.tool_settings.mesh_select_mode[0] = True
bpy.context.scene.tool_settings.mesh_select_mode[1] = False
bpy.context.scene.tool_settings.mesh_select_mode[2] = False
def restore_selection_mode(self):
"""Restore the previously saved selection mode."""
for i, mode in enumerate(self.old_selection_modes):
bpy.context.scene.tool_settings.mesh_select_mode[i] = mode
def execute(self, context):
"""Create a star mesh with modifiers."""
bpy.ops.mesh.primitive_circle_add(
vertices=self.points * 2,
radius=self.inner_radius,
fill_type="NGON",
calc_uvs=True, # this always gives us a circle even if we move verts afterwards
enter_editmode=True,
)
# select all vertices, deselect every other one and then scale
self.set_vertex_selection_mode()
bpy.ops.mesh.select_all(action="SELECT")
bpy.ops.mesh.select_nth(offset=1) # also known as "checker deselect"
R = self.outer_radius / self.inner_radius
bpy.ops.transform.resize(value=(R, R, R))
# select all and create a uv map.smart_project even works if the camera is not aligned
bpy.ops.mesh.select_all(action="SELECT")
bpy.ops.uv.smart_project(rotate_method="AXIS_ALIGNED_X")
self.restore_selection_mode()
bpy.ops.object.mode_set(mode="OBJECT")
# add solidify modifier
mod = context.active_object.modifiers.new(name="Solidify", type="SOLIDIFY")
mod.thickness = 0.1
# add a bevel modifier
mod = context.active_object.modifiers.new(name="Bevel", type="BEVEL")
mod.offset_type = "WIDTH"
mod.width = 0.03
mod.segments = 5
return {"FINISHED"}
@classmethod
def poll(cls, context):
"""Enable operator only in Object mode."""
return context.mode == "OBJECT"
# Note: best practice is to put all imports at the beginning
# but we want make a clear distinction between operator
# implementation and registration.
from bpy.utils import register_class, unregister_class
from bpy.types import VIEW3D_MT_add
def menu_func(self, context):
"""Add the star operator to the Object menu."""
self.layout.operator(OBJECT_OT_add_star.bl_idname)
def register():
"""Register the add-on classes and menu."""
register_class(OBJECT_OT_add_star)
VIEW3D_MT_add.append(menu_func)
def unregister():
"""Unregister the add-on classes and menu."""
VIEW3D_MT_add.remove(menu_func)
unregister_class(OBJECT_OT_add_star)
if __name__ == "__main__":
register()