1 # SPDX-FileCopyrightText: 2016-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 "name": "Surface: Plane / Cone/ Star / Wedge",
7 "description": "Create a NURBS surface plane",
8 "author": "Folkert de Vries",
10 "blender": (2, 80, 0),
11 "location": "View3D > Add > Surface",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
14 "category": "Add Mesh"
19 to add a surface star, plane or cone, go to add Menu > Surface > Star, Plane or Cone
20 next parameters like scale and u and v resolution can be adjusted in the toolshelf
22 have fun using this add-on
26 from bpy
.props
import (
30 from bpy
.types
import Operator
33 # generic class for inheritance
34 class MakeSurfaceHelpers
:
35 # get input for size and resolution
38 description
="Size of the object",
46 description
="Surface resolution in u direction",
53 description
="Surface resolution in v direction",
60 def poll(cls
, context
):
61 return context
.mode
== 'OBJECT'
63 def draw(self
, context
):
65 layout
.prop(self
, "size")
67 col
= layout
.column(align
=True)
68 col
.prop(self
, "res_u")
69 col
.prop(self
, "res_v")
72 class MakeSurfaceWedge(Operator
, MakeSurfaceHelpers
):
73 bl_idname
= "object.add_surface_wedge"
74 bl_label
= "Add Surface Wedge"
75 bl_description
= "Construct a Surface Wedge"
76 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
78 def execute(self
, context
):
85 bpy
.ops
.object.add_surface_plane()
86 # save some time, by getting instant access to those values
87 ao
= context
.active_object
88 point
= ao
.data
.splines
[0].points
90 # rotate 90 degrees on the z axis
91 ao
.rotation_euler
[0] = 0.0
92 ao
.rotation_euler
[1] = 0.0
93 ao
.rotation_euler
[2] = 1.570796
95 # go into edit mode and deselect
96 bpy
.ops
.object.mode_set(mode
='EDIT')
97 bpy
.ops
.curve
.select_all(action
='DESELECT')
99 # select points 0 and 1, and extrudde them
100 # declaring ao and point again seems necessary...
101 ao
= context
.active_object
102 point
= ao
.data
.splines
[0].points
103 point
[0].select
= True
104 ao
= context
.active_object
105 point
= ao
.data
.splines
[0].points
106 point
[1].select
= True
107 bpy
.ops
.curve
.extrude()
108 # bring extruded points up 1 bu on the z axis, and toggle
109 # cyclic in V direction
110 bpy
.ops
.transform
.translate(value
=(0, 0, 1), constraint_axis
=(False, False, True))
111 bpy
.ops
.curve
.cyclic_toggle(direction
='CYCLIC_V')
113 # get points to the right coords.
114 point
[0].co
= (1.0, 0.0, 1.0, 1.0)
115 point
[1].co
= (-1.0, 0.0, 1.0, 1.0)
116 point
[2].co
= (1.0, -0.5, 0.0, 1.0)
117 point
[3].co
= (-1.0, -0.5, 0.0, 1.0)
118 point
[4].co
= (1.0, 0.5, 0.0, 1.0)
119 point
[5].co
= (-1.0, 0.5, 0.0, 1.0)
121 # go back to object mode
122 bpy
.ops
.object.mode_set(mode
='OBJECT')
123 # get origin to geometry.
124 bpy
.ops
.object.origin_set(type='ORIGIN_GEOMETRY', center
='MEDIAN')
126 context
.active_object
.name
= 'SurfaceWedge'
127 # get the wedge to the 3d cursor.
128 context
.active_object
.location
= context
.scene
.cursor
.location
129 bpy
.ops
.transform
.resize(value
=(size
, size
, size
))
131 # adjust resolution in u and v direction
132 context
.active_object
.data
.resolution_u
= res_u
133 context
.active_object
.data
.resolution_v
= res_v
138 class MakeSurfaceCone(Operator
, MakeSurfaceHelpers
):
139 bl_idname
= "object.add_surface_cone"
140 bl_label
= "Add Surface Cone"
141 bl_description
= "Construct a Surface Cone"
142 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
144 def execute(self
, context
):
149 # add basemesh, a nurbs torus
150 bpy
.ops
.surface
.primitive_nurbs_surface_torus_add(location
=(0, 0, 0))
151 # get active object and active object name
153 ao
= context
.active_object
156 bpy
.ops
.object.mode_set(mode
='EDIT')
158 bpy
.ops
.curve
.select_all(action
='DESELECT')
159 # too shorten a lot of lines
160 point
= ao
.data
.splines
[0].points
163 for i
in range(0, 63):
164 if point
[i
].co
.z
== 0.0:
165 point
[i
].select
= True
167 # select non-middle points and delete them
168 bpy
.ops
.curve
.select_all(action
='INVERT')
169 bpy
.ops
.curve
.delete(type='VERT')
170 # declaring this again seems necessary...
171 point
= ao
.data
.splines
[0].points
172 # list of points to be in center, and 2 bu'' s higher
174 ToKeep
= [1, 3, 5, 7, 9, 11, 13, 15, 17]
175 for i
in range(0, len(ToKeep
) - 1):
176 point
[ToKeep
[i
]].select
= True
178 bpy
.ops
.transform
.resize(value
=(0, 0, 0))
179 bpy
.ops
.curve
.cyclic_toggle(direction
='CYCLIC_U')
180 bpy
.ops
.transform
.translate(value
=(0, 0, 2))
182 # to make cone visible
183 bpy
.ops
.object.editmode_toggle()
184 bpy
.ops
.object.editmode_toggle()
186 context
.active_object
.name
= 'SurfaceCone'
187 # go back to object mode
188 bpy
.ops
.object.editmode_toggle()
189 # bring object to cursor
190 bpy
.ops
.object.mode_set(mode
='OBJECT')
191 context
.active_object
.location
= context
.scene
.cursor
.location
193 bpy
.ops
.transform
.resize(value
=(size
, size
, size
))
195 # adjust resolution in u and v direction
196 context
.active_object
.data
.resolution_u
= res_u
197 context
.active_object
.data
.resolution_v
= res_v
202 class MakeSurfaceStar(Operator
, MakeSurfaceHelpers
):
203 bl_idname
= "object.add_surface_star"
204 bl_label
= "Add Surface Star"
205 bl_description
= "Construct a Surface Star"
206 bl_options
= {'REGISTER', 'UNDO'}
208 def execute(self
, context
):
213 # add surface circle:
214 bpy
.ops
.surface
.primitive_nurbs_surface_circle_add(location
=(0, 0, 0))
215 # we got 8 points, we need 40 points.
217 ao
= context
.active_object
219 bpy
.ops
.object.mode_set(mode
='EDIT')
221 bpy
.ops
.curve
.select_all(action
='DESELECT')
222 # select point 0 and 1, and subdivide
223 point
= ao
.data
.splines
[0].points
225 point
[0].select
= True
226 point
[1].select
= True
227 bpy
.ops
.curve
.subdivide()
228 bpy
.ops
.curve
.select_all(action
='DESELECT')
230 # select point 2 and 3, and subdivide
231 point
[2].select
= True
232 point
[3].select
= True
233 bpy
.ops
.curve
.subdivide()
234 bpy
.ops
.curve
.select_all(action
='DESELECT')
237 (0.5, 0.0, 0.25, 1.0),
238 (0.80901700258255, 0.5877853035926819, 0.25, 1.0),
239 (0.1545085906982422, 0.4755282402038574, 0.25, 1.0),
240 (-0.30901703238487244, 0.9510565400123596, 0.25, 1.0),
241 (-0.4045085608959198, 0.293892502784729, 0.2499999850988388, 1.0),
242 (-1.0, 0.0, 0.25, 1.0),
243 (-0.4045085608959198, -0.293892502784729, 0.2499999850988388, 1.0),
244 (-0.30901703238487244, -0.9510565400123596, 0.25, 1.0),
245 (0.1545085906982422, -0.4755282402038574, 0.25, 1.0),
246 (0.8090166449546814, -0.5877856612205505, 0.2499999850988388, 1.0)
248 for i
in range(0, 10):
249 context
.active_object
.data
.splines
[0].points
[i
].co
= ListOfCoords
[i
]
251 # now select all, and subdivide till 40 points is reached:
252 bpy
.ops
.curve
.select_all(action
='SELECT')
253 bpy
.ops
.curve
.subdivide()
254 bpy
.ops
.curve
.subdivide()
255 bpy
.ops
.curve
.subdivide()
258 bpy
.ops
.curve
.extrude(mode
='TRANSLATION')
259 # bring extruded part up
260 bpy
.ops
.transform
.translate(
262 constraint_axis
=(False, False, True)
265 bpy
.ops
.curve
.switch_direction()
266 # go back to object mode
267 bpy
.ops
.object.mode_set(mode
='OBJECT')
269 bpy
.ops
.object.origin_set(type='ORIGIN_GEOMETRY', center
='MEDIAN')
270 # get object to 3d cursor
271 context
.active_object
.location
= context
.scene
.cursor
.location
273 ao
.name
= 'SurfaceStar'
275 bpy
.ops
.transform
.resize(value
=(size
, size
, size
))
277 # adjust resolution in u and v direction
278 context
.active_object
.data
.resolution_u
= res_u
279 context
.active_object
.data
.resolution_v
= res_v
284 class MakeSurfacePlane(Operator
, MakeSurfaceHelpers
):
285 bl_idname
= "object.add_surface_plane"
286 bl_label
= "Add Surface Plane"
287 bl_description
= "Construct a Surface Plane"
288 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
290 def execute(self
, context
):
295 bpy
.ops
.surface
.primitive_nurbs_surface_surface_add() # add the base mesh, a NURBS Surface
297 bpy
.ops
.transform
.resize(
298 value
=(1, 1, 0.0001),
299 constraint_axis
=(False, False, True)
302 # added surface has 16 points
304 # deleting points to get plane shape
305 bpy
.ops
.object.mode_set(mode
='EDIT')
306 bpy
.ops
.curve
.select_all(action
='DESELECT')
308 context
.active_object
.data
.splines
[0].points
[0].select
= True
309 context
.active_object
.data
.splines
[0].points
[1].select
= True
310 context
.active_object
.data
.splines
[0].points
[2].select
= True
311 context
.active_object
.data
.splines
[0].points
[3].select
= True
312 bpy
.ops
.curve
.delete(type='VERT')
314 context
.active_object
.data
.splines
[0].points
[8].select
= True
315 context
.active_object
.data
.splines
[0].points
[9].select
= True
316 context
.active_object
.data
.splines
[0].points
[10].select
= True
317 context
.active_object
.data
.splines
[0].points
[11].select
= True
318 bpy
.ops
.curve
.delete(type='VERT')
320 context
.active_object
.data
.splines
[0].points
[0].select
= True
321 context
.active_object
.data
.splines
[0].points
[4].select
= True
322 bpy
.ops
.curve
.delete(type='VERT')
323 context
.active_object
.data
.splines
[0].points
[2].select
= True
324 context
.active_object
.data
.splines
[0].points
[5].select
= True
325 bpy
.ops
.curve
.delete(type='VERT')
328 context
.active_object
.name
= "SurfacePlane"
330 bpy
.ops
.curve
.select_all(action
='SELECT')
331 # bringing origin to center:
332 bpy
.ops
.object.mode_set(mode
='OBJECT')
333 bpy
.ops
.object.origin_set(type='ORIGIN_GEOMETRY', center
='MEDIAN')
335 bpy
.ops
.object.transform_apply(location
=False,rotation
=False,scale
=True)
337 # bring object to 3d cursor
338 bpy
.ops
.object.mode_set(mode
='OBJECT')
339 context
.active_object
.location
= context
.scene
.cursor
.location
340 bpy
.ops
.transform
.resize(value
=(size
, size
, size
))
342 # adjust resolution in u and v direction
343 context
.active_object
.data
.resolution_u
= res_u
344 context
.active_object
.data
.resolution_v
= res_v
349 class SmoothXtimes(Operator
):
350 bl_idname
= "curve.smooth_x_times"
351 bl_label
= "Smooth X Times"
352 #bl_space_type = "VIEW_3D"
353 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
356 # lets you smooth till a thousand times. this is normally difficult, because
357 # you have to press w, click, press w, click etc.
361 name
="Smooth x Times",
365 description
="Smooth amount"
369 def poll(cls
, context
):
370 return context
.mode
== 'EDIT_SURFACE'
372 def execute(self
, context
):
375 for i
in range(1, times
):
376 bpy
.ops
.curve
.smooth()
391 from bpy
.utils
import register_class
396 from bpy
.utils
import unregister_class
397 for cls
in reversed(classes
):
398 unregister_class(cls
)
400 if __name__
== "__main__":