mirror of
https://github.com/blender/blender-addons.git
synced 2025-08-20 13:22:58 +00:00
400 lines
13 KiB
Python
400 lines
13 KiB
Python
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
bl_info = {
|
|
"name": "Surface: Plane / Cone/ Star / Wedge",
|
|
"description": "Create a NURBS surface plane",
|
|
"author": "Folkert de Vries",
|
|
"version": (1, 0, 2),
|
|
"blender": (2, 80, 0),
|
|
"location": "View3D > Add > Surface",
|
|
"warning": "",
|
|
"doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
|
|
"category": "Add Mesh"
|
|
}
|
|
|
|
"""
|
|
Info:
|
|
to add a surface star, plane or cone, go to add Menu > Surface > Star, Plane or Cone
|
|
next parameters like scale and u and v resolution can be adjusted in the toolshelf
|
|
|
|
have fun using this add-on
|
|
"""
|
|
|
|
import bpy
|
|
from bpy.props import (
|
|
FloatProperty,
|
|
IntProperty,
|
|
)
|
|
from bpy.types import Operator
|
|
|
|
|
|
# generic class for inheritance
|
|
class MakeSurfaceHelpers:
|
|
# get input for size and resolution
|
|
size : FloatProperty(
|
|
name="Size",
|
|
description="Size of the object",
|
|
default=1.0,
|
|
min=0.01,
|
|
max=100.0,
|
|
unit="LENGTH",
|
|
)
|
|
res_u : IntProperty(
|
|
name="Resolution U",
|
|
description="Surface resolution in u direction",
|
|
default=1,
|
|
min=1,
|
|
max=500,
|
|
)
|
|
res_v : IntProperty(
|
|
name="Resolution V",
|
|
description="Surface resolution in v direction",
|
|
default=1,
|
|
min=1,
|
|
max=500,
|
|
)
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.mode == 'OBJECT'
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.prop(self, "size")
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(self, "res_u")
|
|
col.prop(self, "res_v")
|
|
|
|
|
|
class MakeSurfaceWedge(Operator, MakeSurfaceHelpers):
|
|
bl_idname = "object.add_surface_wedge"
|
|
bl_label = "Add Surface Wedge"
|
|
bl_description = "Construct a Surface Wedge"
|
|
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
|
|
|
|
def execute(self, context):
|
|
# variables
|
|
size = self.size
|
|
res_u = self.res_u
|
|
res_v = self.res_v
|
|
|
|
# add a surface Plane
|
|
bpy.ops.object.add_surface_plane()
|
|
# save some time, by getting instant access to those values
|
|
ao = context.active_object
|
|
point = ao.data.splines[0].points
|
|
|
|
# rotate 90 degrees on the z axis
|
|
ao.rotation_euler[0] = 0.0
|
|
ao.rotation_euler[1] = 0.0
|
|
ao.rotation_euler[2] = 1.570796
|
|
|
|
# go into edit mode and deselect
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
bpy.ops.curve.select_all(action='DESELECT')
|
|
|
|
# select points 0 and 1, and extrudde them
|
|
# declaring ao and point again seems necessary...
|
|
ao = context.active_object
|
|
point = ao.data.splines[0].points
|
|
point[0].select = True
|
|
ao = context.active_object
|
|
point = ao.data.splines[0].points
|
|
point[1].select = True
|
|
bpy.ops.curve.extrude()
|
|
# bring extruded points up 1 bu on the z axis, and toggle
|
|
# cyclic in V direction
|
|
bpy.ops.transform.translate(value=(0, 0, 1), constraint_axis=(False, False, True))
|
|
bpy.ops.curve.cyclic_toggle(direction='CYCLIC_V')
|
|
|
|
# get points to the right coords.
|
|
point[0].co = (1.0, 0.0, 1.0, 1.0)
|
|
point[1].co = (-1.0, 0.0, 1.0, 1.0)
|
|
point[2].co = (1.0, -0.5, 0.0, 1.0)
|
|
point[3].co = (-1.0, -0.5, 0.0, 1.0)
|
|
point[4].co = (1.0, 0.5, 0.0, 1.0)
|
|
point[5].co = (-1.0, 0.5, 0.0, 1.0)
|
|
|
|
# go back to object mode
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
# get origin to geometry.
|
|
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
|
|
# change name
|
|
context.active_object.name = 'SurfaceWedge'
|
|
# get the wedge to the 3d cursor.
|
|
context.active_object.location = context.scene.cursor.location
|
|
bpy.ops.transform.resize(value=(size, size, size))
|
|
|
|
# adjust resolution in u and v direction
|
|
context.active_object.data.resolution_u = res_u
|
|
context.active_object.data.resolution_v = res_v
|
|
|
|
return{'FINISHED'}
|
|
|
|
|
|
class MakeSurfaceCone(Operator, MakeSurfaceHelpers):
|
|
bl_idname = "object.add_surface_cone"
|
|
bl_label = "Add Surface Cone"
|
|
bl_description = "Construct a Surface Cone"
|
|
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
|
|
|
|
def execute(self, context):
|
|
size = self.size
|
|
res_u = self.res_u
|
|
res_v = self.res_v
|
|
|
|
# add basemesh, a nurbs torus
|
|
bpy.ops.surface.primitive_nurbs_surface_torus_add(location=(0, 0, 0))
|
|
# get active object and active object name
|
|
|
|
ao = context.active_object
|
|
|
|
# go to edit mode
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
# deselect all
|
|
bpy.ops.curve.select_all(action='DESELECT')
|
|
# too shorten a lot of lines
|
|
point = ao.data.splines[0].points
|
|
# get middle points
|
|
|
|
for i in range(0, 63):
|
|
if point[i].co.z == 0.0:
|
|
point[i].select = True
|
|
|
|
# select non-middle points and delete them
|
|
bpy.ops.curve.select_all(action='INVERT')
|
|
bpy.ops.curve.delete(type='VERT')
|
|
# declaring this again seems necessary...
|
|
point = ao.data.splines[0].points
|
|
# list of points to be in center, and 2 bu'' s higher
|
|
|
|
ToKeep = [1, 3, 5, 7, 9, 11, 13, 15, 17]
|
|
for i in range(0, len(ToKeep) - 1):
|
|
point[ToKeep[i]].select = True
|
|
|
|
bpy.ops.transform.resize(value=(0, 0, 0))
|
|
bpy.ops.curve.cyclic_toggle(direction='CYCLIC_U')
|
|
bpy.ops.transform.translate(value=(0, 0, 2))
|
|
|
|
# to make cone visible
|
|
bpy.ops.object.editmode_toggle()
|
|
bpy.ops.object.editmode_toggle()
|
|
# change name
|
|
context.active_object.name = 'SurfaceCone'
|
|
# go back to object mode
|
|
bpy.ops.object.editmode_toggle()
|
|
# bring object to cursor
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
context.active_object.location = context.scene.cursor.location
|
|
# adjust size
|
|
bpy.ops.transform.resize(value=(size, size, size))
|
|
|
|
# adjust resolution in u and v direction
|
|
context.active_object.data.resolution_u = res_u
|
|
context.active_object.data.resolution_v = res_v
|
|
|
|
return{'FINISHED'}
|
|
|
|
|
|
class MakeSurfaceStar(Operator, MakeSurfaceHelpers):
|
|
bl_idname = "object.add_surface_star"
|
|
bl_label = "Add Surface Star"
|
|
bl_description = "Construct a Surface Star"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
size = self.size
|
|
res_u = self.res_u
|
|
res_v = self.res_v
|
|
|
|
# add surface circle:
|
|
bpy.ops.surface.primitive_nurbs_surface_circle_add(location=(0, 0, 0))
|
|
# we got 8 points, we need 40 points.
|
|
# get active object
|
|
ao = context.active_object
|
|
# enter edtimode
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
# deselect all
|
|
bpy.ops.curve.select_all(action='DESELECT')
|
|
# select point 0 and 1, and subdivide
|
|
point = ao.data.splines[0].points
|
|
|
|
point[0].select = True
|
|
point[1].select = True
|
|
bpy.ops.curve.subdivide()
|
|
bpy.ops.curve.select_all(action='DESELECT')
|
|
|
|
# select point 2 and 3, and subdivide
|
|
point[2].select = True
|
|
point[3].select = True
|
|
bpy.ops.curve.subdivide()
|
|
bpy.ops.curve.select_all(action='DESELECT')
|
|
|
|
ListOfCoords = [
|
|
(0.5, 0.0, 0.25, 1.0),
|
|
(0.80901700258255, 0.5877853035926819, 0.25, 1.0),
|
|
(0.1545085906982422, 0.4755282402038574, 0.25, 1.0),
|
|
(-0.30901703238487244, 0.9510565400123596, 0.25, 1.0),
|
|
(-0.4045085608959198, 0.293892502784729, 0.2499999850988388, 1.0),
|
|
(-1.0, 0.0, 0.25, 1.0),
|
|
(-0.4045085608959198, -0.293892502784729, 0.2499999850988388, 1.0),
|
|
(-0.30901703238487244, -0.9510565400123596, 0.25, 1.0),
|
|
(0.1545085906982422, -0.4755282402038574, 0.25, 1.0),
|
|
(0.8090166449546814, -0.5877856612205505, 0.2499999850988388, 1.0)
|
|
]
|
|
for i in range(0, 10):
|
|
context.active_object.data.splines[0].points[i].co = ListOfCoords[i]
|
|
|
|
# now select all, and subdivide till 40 points is reached:
|
|
bpy.ops.curve.select_all(action='SELECT')
|
|
bpy.ops.curve.subdivide()
|
|
bpy.ops.curve.subdivide()
|
|
bpy.ops.curve.subdivide()
|
|
|
|
# extrude the star
|
|
bpy.ops.curve.extrude(mode='TRANSLATION')
|
|
# bring extruded part up
|
|
bpy.ops.transform.translate(
|
|
value=(0, 0, 0.5),
|
|
constraint_axis=(False, False, True)
|
|
)
|
|
# flip normals
|
|
bpy.ops.curve.switch_direction()
|
|
# go back to object mode
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
# origin to geometry
|
|
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
|
|
# get object to 3d cursor
|
|
context.active_object.location = context.scene.cursor.location
|
|
# change name
|
|
ao.name = 'SurfaceStar'
|
|
# adjust size
|
|
bpy.ops.transform.resize(value=(size, size, size))
|
|
|
|
# adjust resolution in u and v direction
|
|
context.active_object.data.resolution_u = res_u
|
|
context.active_object.data.resolution_v = res_v
|
|
|
|
return{'FINISHED'}
|
|
|
|
|
|
class MakeSurfacePlane(Operator, MakeSurfaceHelpers):
|
|
bl_idname = "object.add_surface_plane"
|
|
bl_label = "Add Surface Plane"
|
|
bl_description = "Construct a Surface Plane"
|
|
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
|
|
|
|
def execute(self, context):
|
|
size = self.size
|
|
res_u = self.res_u
|
|
res_v = self.res_v
|
|
|
|
bpy.ops.surface.primitive_nurbs_surface_surface_add() # add the base mesh, a NURBS Surface
|
|
|
|
bpy.ops.transform.resize(
|
|
value=(1, 1, 0.0001),
|
|
constraint_axis=(False, False, True)
|
|
) # make it flat
|
|
|
|
# added surface has 16 points
|
|
|
|
# deleting points to get plane shape
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
bpy.ops.curve.select_all(action='DESELECT')
|
|
|
|
context.active_object.data.splines[0].points[0].select = True
|
|
context.active_object.data.splines[0].points[1].select = True
|
|
context.active_object.data.splines[0].points[2].select = True
|
|
context.active_object.data.splines[0].points[3].select = True
|
|
bpy.ops.curve.delete(type='VERT')
|
|
|
|
context.active_object.data.splines[0].points[8].select = True
|
|
context.active_object.data.splines[0].points[9].select = True
|
|
context.active_object.data.splines[0].points[10].select = True
|
|
context.active_object.data.splines[0].points[11].select = True
|
|
bpy.ops.curve.delete(type='VERT')
|
|
|
|
context.active_object.data.splines[0].points[0].select = True
|
|
context.active_object.data.splines[0].points[4].select = True
|
|
bpy.ops.curve.delete(type='VERT')
|
|
context.active_object.data.splines[0].points[2].select = True
|
|
context.active_object.data.splines[0].points[5].select = True
|
|
bpy.ops.curve.delete(type='VERT')
|
|
|
|
# assigning name
|
|
context.active_object.name = "SurfacePlane"
|
|
# select all
|
|
bpy.ops.curve.select_all(action='SELECT')
|
|
# bringing origin to center:
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
|
|
# transform scale
|
|
bpy.ops.object.transform_apply(location=False,rotation=False,scale=True)
|
|
|
|
# bring object to 3d cursor
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
context.active_object.location = context.scene.cursor.location
|
|
bpy.ops.transform.resize(value=(size, size, size))
|
|
|
|
# adjust resolution in u and v direction
|
|
context.active_object.data.resolution_u = res_u
|
|
context.active_object.data.resolution_v = res_v
|
|
|
|
return{'FINISHED'}
|
|
|
|
|
|
class SmoothXtimes(Operator):
|
|
bl_idname = "curve.smooth_x_times"
|
|
bl_label = "Smooth X Times"
|
|
#bl_space_type = "VIEW_3D"
|
|
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
|
|
|
|
# use of this class:
|
|
# lets you smooth till a thousand times. this is normally difficult, because
|
|
# you have to press w, click, press w, click etc.
|
|
|
|
# get values
|
|
times : IntProperty(
|
|
name="Smooth x Times",
|
|
min=1,
|
|
max=1000,
|
|
default=1,
|
|
description="Smooth amount"
|
|
)
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.mode == 'EDIT_SURFACE'
|
|
|
|
def execute(self, context):
|
|
# smooth times
|
|
times = self.times
|
|
for i in range(1, times):
|
|
bpy.ops.curve.smooth()
|
|
|
|
return{'FINISHED'}
|
|
|
|
# Register
|
|
classes = [
|
|
#MakeSurfaceHelpers,
|
|
MakeSurfacePlane,
|
|
MakeSurfaceCone,
|
|
MakeSurfaceStar,
|
|
MakeSurfaceWedge,
|
|
SmoothXtimes
|
|
]
|
|
|
|
def register():
|
|
from bpy.utils import register_class
|
|
for cls in classes:
|
|
register_class(cls)
|
|
|
|
def unregister():
|
|
from bpy.utils import unregister_class
|
|
for cls in reversed(classes):
|
|
unregister_class(cls)
|
|
|
|
if __name__ == "__main__":
|
|
register()
|