Newer
Older
# check for zero angles, not sure if it is a great fix
if vec_A.length != 0 and vec_B.length != 0:
angle = vec_A.angle(vec_B) / pi
edge_new_length = (Vector(verts_middle_position_co) - sp[1][i]).length
else:
angle = 0
edge_new_length = 0
CoDEmanX
committed
# If after moving the verts to the middle point, the segment doesn't stretch too much
if edge_new_length <= loop_segment_dist * 1.5 * \
self.join_stretch_factor and angle < 0.25 * self.join_stretch_factor:
CoDEmanX
committed
# Avoid joining when the actual loop must be merged with the original mesh
if not (self.selection_U_exists and i == 0) and \
not (self.selection_U2_exists and i == len(surface_splines_parsed[0]) - 1):
CoDEmanX
committed
# Change the coords of both verts to the middle position
surface_splines_parsed[0][i] = verts_middle_position_co
surface_splines_parsed[len(surface_splines_parsed) - 1][i] = verts_middle_position_co
CoDEmanX
committed
# Delete object with control points and object from grease pencil conversion
bpy.ops.object.delete({"selected_objects": [ob_ctrl_pts]})
CoDEmanX
committed
bpy.ops.object.delete({"selected_objects": splines_U_objects})
CoDEmanX
committed
CoDEmanX
committed
all_surface_verts_co = []
for i in range(0, len(surface_splines_parsed)):
# Get coords of all verts and make a list with them
for pt_co in surface_splines_parsed[i]:
all_surface_verts_co.append(pt_co)
CoDEmanX
committed
all_surface_faces = []
for i in range(0, len(all_surface_verts_co) - len(surface_splines_parsed[0])):
if ((i + 1) / len(surface_splines_parsed[0]) != int((i + 1) / len(surface_splines_parsed[0]))):
all_surface_faces.append(
[i + 1, i, i + len(surface_splines_parsed[0]),
i + len(surface_splines_parsed[0]) + 1]
)
# Build the mesh
surf_me_name = "SURFSKIO_surface"
me_surf = bpy.data.meshes.new(surf_me_name)
me_surf.from_pydata(all_surface_verts_co, [], all_surface_faces)
ob_surface = object_utils.object_data_add(context, me_surf)
Vladimir Spivak(cwolf3d)
committed
ob_surface.location = (0.0, 0.0, 0.0)
ob_surface.rotation_euler = (0.0, 0.0, 0.0)
ob_surface.scale = (1.0, 1.0, 1.0)
CoDEmanX
committed
# Select all the "unselected but participating" verts, from closed selection
# or double selections with middle-vertex, for later join with remove doubles
for v_idx in single_unselected_verts:
self.main_object.data.vertices[v_idx].select = True
CoDEmanX
committed
# Join the new mesh to the main object
bpy.context.view_layer.objects.active = self.main_object
CoDEmanX
committed
bpy.ops.object.join('INVOKE_REGION_WIN')
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
CoDEmanX
committed
bpy.ops.mesh.remove_doubles('INVOKE_REGION_WIN', threshold=0.0001)
bpy.ops.mesh.normals_make_consistent('INVOKE_REGION_WIN', inside=False)
bpy.ops.mesh.select_all('INVOKE_REGION_WIN', action='DESELECT')
Spivak Vladimir (cwolf3d)
committed
self.update()
Spivak Vladimir (cwolf3d)
committed
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
def update(self):
try:
global global_offset
shrinkwrap = self.main_object.modifiers["Shrinkwrap"]
shrinkwrap.offset = global_offset
bpy.context.scene.bsurfaces.SURFSK_Shrinkwrap_offset = global_offset
except:
Spivak Vladimir (cwolf3d)
committed
try:
global global_color
material = makeMaterial("BSurfaceMesh", global_color)
if self.main_object.data.materials:
self.main_object.data.materials[0] = material
else:
self.main_object.data.materials.append(material)
bpy.context.scene.bsurfaces.SURFSK_mesh_color = global_color
except:
pass
Spivak Vladimir (cwolf3d)
committed
global global_in_front
self.main_object.show_in_front = global_in_front
bpy.context.scene.bsurfaces.SURFSK_in_front = global_in_front
except:
pass
Spivak Vladimir (cwolf3d)
committed
global global_show_wire
self.main_object.show_wire = global_show_wire
bpy.context.scene.bsurfaces.SURFSK_show_wire = global_show_wire
except:
pass
Spivak Vladimir (cwolf3d)
committed
try:
global global_shade_smooth
if global_shade_smooth:
bpy.ops.object.shade_smooth()
else:
bpy.ops.object.shade_flat()
bpy.context.scene.bsurfaces.SURFSK_shade_smooth = global_shade_smooth
except:
pass
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
return{'FINISHED'}
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
global global_mesh_object
global_mesh_object = bpy.context.scene.bsurfaces.SURFSK_mesh.name
bpy.data.objects[global_mesh_object].select_set(True)
self.main_object = bpy.data.objects[global_mesh_object]
bpy.context.view_layer.objects.active = self.main_object
bsurfaces_props = bpy.context.scene.bsurfaces
except:
self.report({'WARNING'}, "Specify the name of the object with retopology")
return{"CANCELLED"}
bpy.context.view_layer.objects.active = self.main_object
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
self.update()
Spivak Vladimir (cwolf3d)
committed
bpy.ops.wm.context_set_value(data_path='tool_settings.mesh_select_mode',
value='True, False, False')
CoDEmanX
committed
# Build splines from the "last saved splines".
last_saved_curve = bpy.data.curves.new('SURFSKIO_last_crv', 'CURVE')
self.main_splines = bpy.data.objects.new('SURFSKIO_last_crv', last_saved_curve)
bpy.context.collection.objects.link(self.main_splines)
CoDEmanX
committed
last_saved_curve.dimensions = "3D"
CoDEmanX
committed
for sp in self.last_strokes_splines_coords:
spline = self.main_splines.data.splines.new('BEZIER')
# less one because one point is added when the spline is created
spline.bezier_points.add(len(sp) - 1)
for p in range(0, len(sp)):
spline.bezier_points[p].co = [sp[p][0], sp[p][1], sp[p][2]]
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
CoDEmanX
committed
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
self.main_splines.select_set(True)
bpy.context.view_layer.objects.active = self.main_splines
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='EDIT')
CoDEmanX
committed
bpy.ops.curve.select_all('INVOKE_REGION_WIN', action='SELECT')
# Important to make it vector first and then automatic, otherwise the
# tips handles get too big and distort the shrinkwrap results later
bpy.ops.curve.handle_type_set(type='VECTOR')
bpy.ops.curve.handle_type_set('INVOKE_REGION_WIN', type='AUTOMATIC')
bpy.ops.curve.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
CoDEmanX
committed
self.main_splines.name = "SURFSKIO_temp_strokes"
CoDEmanX
committed
if self.is_crosshatch:
strokes_for_crosshatch = True
strokes_for_rectangular_surface = False
else:
strokes_for_rectangular_surface = True
strokes_for_crosshatch = False
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
CoDEmanX
committed
if strokes_for_rectangular_surface:
self.rectangular_surface(context)
self.crosshatch_surface_execute(context)
Spivak Vladimir (cwolf3d)
committed
#Set Shade smooth to new polygons
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
global global_shade_smooth
if global_shade_smooth:
bpy.ops.object.shade_smooth()
else:
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
if self.keep_strokes:
self.main_splines.name = "keep_strokes"
self.main_splines.data.bevel_depth = 0.001
if "keep_strokes_material" in bpy.data.materials :
self.main_splines.data.materials.append(bpy.data.materials["keep_strokes_material"])
else:
mat = bpy.data.materials.new("keep_strokes_material")
mat.diffuse_color = (1, 0, 0, 0)
mat.specular_color = (1, 0, 0)
mat.specular_intensity = 0.0
mat.roughness = 0.0
self.main_splines.data.materials.append(mat)
else:
bpy.ops.object.delete({"selected_objects": [self.main_splines]})
Spivak Vladimir (cwolf3d)
committed
# Delete grease pencil strokes
if self.strokes_type == "GP_STROKES" and not self.stopping_errors:
bpy.context.scene.bsurfaces.SURFSK_gpencil.data.layers.active.clear()
except:
pass
Spivak Vladimir (cwolf3d)
committed
# Delete annotations
if self.strokes_type == "GP_ANNOTATION" and not self.stopping_errors:
bpy.context.annotation_data.layers.active.clear()
except:
pass
bsurfaces_props = bpy.context.scene.bsurfaces
bsurfaces_props.SURFSK_edges_U = self.edges_U
bsurfaces_props.SURFSK_edges_V = self.edges_V
bsurfaces_props.SURFSK_cyclic_cross = self.cyclic_cross
bsurfaces_props.SURFSK_cyclic_follow = self.cyclic_follow
bsurfaces_props.SURFSK_automatic_join = self.automatic_join
bsurfaces_props.SURFSK_loops_on_strokes = self.loops_on_strokes
bsurfaces_props.SURFSK_keep_strokes = self.keep_strokes
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.context.view_layer.objects.active = self.main_object
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
self.update()
Spivak Vladimir (cwolf3d)
committed
CoDEmanX
committed
def invoke(self, context, event):
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
bsurfaces_props = bpy.context.scene.bsurfaces
self.cyclic_cross = bsurfaces_props.SURFSK_cyclic_cross
self.cyclic_follow = bsurfaces_props.SURFSK_cyclic_follow
self.automatic_join = bsurfaces_props.SURFSK_automatic_join
self.loops_on_strokes = bsurfaces_props.SURFSK_loops_on_strokes
self.keep_strokes = bsurfaces_props.SURFSK_keep_strokes
global global_mesh_object
global_mesh_object = bpy.context.scene.bsurfaces.SURFSK_mesh.name
bpy.data.objects[global_mesh_object].select_set(True)
self.main_object = bpy.data.objects[global_mesh_object]
bpy.context.view_layer.objects.active = self.main_object
except:
self.report({'WARNING'}, "Specify the name of the object with retopology")
return{"CANCELLED"}
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
self.update()
Spivak Vladimir (cwolf3d)
committed
self.main_object_selected_verts_count = len([v for v in self.main_object.data.vertices if v.select])
bpy.ops.wm.context_set_value(data_path='tool_settings.mesh_select_mode',
value='True, False, False')
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
self.edges_U = bsurfaces_props.SURFSK_edges_U
self.edges_V = bsurfaces_props.SURFSK_edges_V
CoDEmanX
committed
self.is_fill_faces = False
self.stopping_errors = False
self.last_strokes_splines_coords = []
CoDEmanX
committed
# Determine the type of the strokes
self.strokes_type = get_strokes_type(context)
CoDEmanX
committed
# Check if it will be used grease pencil strokes or curves
# If there are strokes to be used
if self.strokes_type == "GP_STROKES" or self.strokes_type == "EXTERNAL_CURVE" or self.strokes_type == "GP_ANNOTATION":
if self.strokes_type == "GP_STROKES":
# Convert grease pencil strokes to curve
global global_gpencil_object
gp = bpy.data.objects[global_gpencil_object]
self.original_curve = conver_gpencil_to_curve(self, context, gp, 'GPensil')
self.using_external_curves = False
Spivak Vladimir (cwolf3d)
committed
elif self.strokes_type == "GP_ANNOTATION":
# Convert grease pencil strokes to curve
gp = bpy.context.annotation_data
self.original_curve = conver_gpencil_to_curve(self, context, gp, 'Annotation')
self.using_external_curves = False
Spivak Vladimir (cwolf3d)
committed
elif self.strokes_type == "EXTERNAL_CURVE":
global global_curve_object
self.original_curve = bpy.data.objects[global_curve_object]
self.using_external_curves = True
CoDEmanX
committed
# Make sure there are no objects left from erroneous
# executions of this operator, with the reserved names used here
for o in bpy.data.objects:
if o.name.find("SURFSKIO_") != -1:
bpy.ops.object.delete({"selected_objects": [o]})
CoDEmanX
committed
bpy.context.view_layer.objects.active = self.original_curve
CoDEmanX
committed
bpy.ops.object.duplicate('INVOKE_REGION_WIN')
CoDEmanX
committed
self.temporary_curve = bpy.context.view_layer.objects.active
CoDEmanX
committed
# Deselect all points of the curve
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
bpy.ops.curve.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
CoDEmanX
committed
# Delete splines with only a single isolated point
for i in range(len(self.temporary_curve.data.splines)):
sp = self.temporary_curve.data.splines[i]
CoDEmanX
committed
if len(sp.bezier_points) == 1:
sp.bezier_points[0].select_control_point = True
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
CoDEmanX
committed
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.context.view_layer.objects.active = self.temporary_curve
CoDEmanX
committed
# Set a minimum number of points for crosshatch
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
# Check if the number of points of each curve has at least the number of points
# of minimum_points_num, which is a bit more than the face-loops limit.
# If not, subdivide to reach at least that number of points
for i in range(len(self.temporary_curve.data.splines)):
sp = self.temporary_curve.data.splines[i]
CoDEmanX
committed
if len(sp.bezier_points) < minimum_points_num:
for bp in sp.bezier_points:
bp.select_control_point = True
CoDEmanX
committed
if (len(sp.bezier_points) - 1) != 0:
# Formula to get the number of cuts that will make a curve
# of N number of points have near to "minimum_points_num"
# points, when subdividing with this number of cuts
subdivide_cuts = int(
(minimum_points_num - len(sp.bezier_points)) /
(len(sp.bezier_points) - 1)
) + 1
CoDEmanX
committed
bpy.ops.curve.subdivide('INVOKE_REGION_WIN', number_cuts=subdivide_cuts)
bpy.ops.curve.select_all('INVOKE_REGION_WIN', action='DESELECT')
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
CoDEmanX
committed
# Detect if the strokes are a crosshatch and do it if it is
self.crosshatch_surface_invoke(self.temporary_curve)
CoDEmanX
committed
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.context.view_layer.objects.active = self.temporary_curve
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
CoDEmanX
committed
# Set a minimum number of points for rectangular surfaces
CoDEmanX
committed
# Check if the number of points of each curve has at least the number of points
# of minimum_points_num, which is a bit more than the face-loops limit.
# If not, subdivide to reach at least that number of points
for i in range(len(self.temporary_curve.data.splines)):
sp = self.temporary_curve.data.splines[i]
CoDEmanX
committed
if len(sp.bezier_points) < minimum_points_num:
for bp in sp.bezier_points:
bp.select_control_point = True
CoDEmanX
committed
if (len(sp.bezier_points) - 1) != 0:
# Formula to get the number of cuts that will make a curve of
# N number of points have near to "minimum_points_num" points,
# when subdividing with this number of cuts
subdivide_cuts = int(
(minimum_points_num - len(sp.bezier_points)) /
(len(sp.bezier_points) - 1)
) + 1
CoDEmanX
committed
bpy.ops.curve.subdivide('INVOKE_REGION_WIN', number_cuts=subdivide_cuts)
bpy.ops.curve.select_all('INVOKE_REGION_WIN', action='DESELECT')
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
CoDEmanX
committed
# Save coordinates of the actual strokes (as the "last saved splines")
for sp_idx in range(len(self.temporary_curve.data.splines)):
self.last_strokes_splines_coords.append([])
for bp_idx in range(len(self.temporary_curve.data.splines[sp_idx].bezier_points)):
coords = self.temporary_curve.matrix_world @ \
self.temporary_curve.data.splines[sp_idx].bezier_points[bp_idx].co
self.last_strokes_splines_coords[sp_idx].append([coords[0], coords[1], coords[2]])
CoDEmanX
committed
# Check for cyclic splines, put the first and last points in the middle of their actual positions
for sp_idx in range(len(self.temporary_curve.data.splines)):
if self.temporary_curve.data.splines[sp_idx].use_cyclic_u is True:
first_p_co = self.last_strokes_splines_coords[sp_idx][0]
last_p_co = self.last_strokes_splines_coords[sp_idx][
len(self.last_strokes_splines_coords[sp_idx]) - 1
]
target_co = [
(first_p_co[0] + last_p_co[0]) / 2,
(first_p_co[1] + last_p_co[1]) / 2,
(first_p_co[2] + last_p_co[2]) / 2
]
CoDEmanX
committed
self.last_strokes_splines_coords[sp_idx][0] = target_co
self.last_strokes_splines_coords[sp_idx][
len(self.last_strokes_splines_coords[sp_idx]) - 1
] = target_co
tuple(self.last_strokes_splines_coords)
CoDEmanX
committed
# Estimation of the average length of the segments between
# each point of the grease pencil strokes.
# Will be useful to determine whether a curve should be made "Cyclic"
segments_lengths_sum = 0
segments_count = 0
random_spline = self.temporary_curve.data.splines[0].bezier_points
for i in range(0, len(random_spline)):
if i != 0 and len(random_spline) - 1 >= i:
segments_lengths_sum += (random_spline[i - 1].co - random_spline[i].co).length
segments_count += 1
CoDEmanX
committed
self.average_gp_segment_length = segments_lengths_sum / segments_count
CoDEmanX
committed
# Delete temporary strokes curve object
bpy.ops.object.delete({"selected_objects": [self.temporary_curve]})
Spivak Vladimir (cwolf3d)
committed
# Set again since "execute()" will turn it again to its initial value
self.execute(context)
CoDEmanX
committed
# Delete grease pencil strokes
if self.strokes_type == "GP_STROKES":
try:
bpy.context.scene.bsurfaces.SURFSK_gpencil.data.layers.active.clear()
except:
pass
Spivak Vladimir (cwolf3d)
committed
# Delete annotation strokes
elif self.strokes_type == "GP_ANNOTATION":
try:
bpy.context.annotation_data.layers.active.clear()
except:
pass
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
bpy.ops.object.delete({"selected_objects": [self.original_curve]})
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
Spivak Vladimir (cwolf3d)
committed
return {"FINISHED"}
else:
return{"CANCELLED"}
CoDEmanX
committed
elif self.strokes_type == "SELECTION_ALONE":
self.is_fill_faces = True
created_faces_count = self.fill_with_faces(self.main_object)
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
self.report({'WARNING'}, "There aren't any strokes attached to the object")
return {"CANCELLED"}
else:
return {"FINISHED"}
CoDEmanX
committed
if self.strokes_type == "EXTERNAL_NO_CURVE":
self.report({'WARNING'}, "The secondary object is not a Curve.")
return{"CANCELLED"}
CoDEmanX
committed
elif self.strokes_type == "MORE_THAN_ONE_EXTERNAL":
self.report({'WARNING'}, "There shouldn't be more than one secondary object selected.")
return{"CANCELLED"}
CoDEmanX
committed
elif self.strokes_type == "SINGLE_GP_STROKE_NO_SELECTION" or \
self.strokes_type == "SINGLE_CURVE_STROKE_NO_SELECTION":
self.report({'WARNING'}, "It's needed at least one stroke and one selection, or two strokes.")
return{"CANCELLED"}
CoDEmanX
committed
elif self.strokes_type == "NO_STROKES":
self.report({'WARNING'}, "There aren't any strokes attached to the object")
CoDEmanX
committed
elif self.strokes_type == "CURVE_WITH_NON_BEZIER_SPLINES":
self.report({'WARNING'}, "All splines must be Bezier.")
return{"CANCELLED"}
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
# ----------------------------
# Init operator
Spivak Vladimir (cwolf3d)
committed
class MESH_OT_SURFSK_init(Operator):
bl_idname = "mesh.surfsk_init"
bl_label = "Bsurfaces initialize"
bl_description = "Add an empty mesh object with useful settings"
Spivak Vladimir (cwolf3d)
committed
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
Spivak Vladimir (cwolf3d)
committed
bs = bpy.context.scene.bsurfaces
Spivak Vladimir (cwolf3d)
committed
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
Spivak Vladimir (cwolf3d)
committed
global global_color
global global_offset
global global_in_front
global global_show_wire
global global_shade_smooth
global global_mesh_object
global global_gpencil_object
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
if bs.SURFSK_mesh == None:
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
mesh = bpy.data.meshes.new('BSurfaceMesh')
mesh_object = object_utils.object_data_add(context, mesh)
mesh_object.select_set(True)
Spivak Vladimir (cwolf3d)
committed
bpy.context.view_layer.objects.active = mesh_object
Spivak Vladimir (cwolf3d)
committed
mesh_object.show_all_edges = True
global_in_front = bpy.context.scene.bsurfaces.SURFSK_in_front
mesh_object.show_in_front = global_in_front
mesh_object.display_type = 'SOLID'
mesh_object.show_wire = True
Spivak Vladimir (cwolf3d)
committed
global_shade_smooth = bpy.context.scene.bsurfaces.SURFSK_shade_smooth
if global_shade_smooth:
bpy.ops.object.shade_smooth()
else:
bpy.ops.object.shade_flat()
Spivak Vladimir (cwolf3d)
committed
global_show_wire = bpy.context.scene.bsurfaces.SURFSK_show_wire
mesh_object.show_wire = global_show_wire
Spivak Vladimir (cwolf3d)
committed
global_color = bpy.context.scene.bsurfaces.SURFSK_mesh_color
material = makeMaterial("BSurfaceMesh", global_color)
Spivak Vladimir (cwolf3d)
committed
mesh_object.data.materials.append(material)
bpy.ops.object.modifier_add(type='SHRINKWRAP')
modifier = mesh_object.modifiers["Shrinkwrap"]
if self.active_object is not None:
modifier.target = self.active_object
modifier.wrap_method = 'TARGET_PROJECT'
modifier.wrap_mode = 'OUTSIDE_SURFACE'
Spivak Vladimir (cwolf3d)
committed
modifier.show_on_cage = True
global_offset = bpy.context.scene.bsurfaces.SURFSK_Shrinkwrap_offset
modifier.offset = global_offset
global_mesh_object = mesh_object.name
bpy.context.scene.bsurfaces.SURFSK_mesh = bpy.data.objects[global_mesh_object]
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
bpy.context.scene.tool_settings.snap_elements = {'FACE'}
bpy.context.scene.tool_settings.use_snap = True
bpy.context.scene.tool_settings.use_snap_self = False
bpy.context.scene.tool_settings.use_snap_align_rotation = True
bpy.context.scene.tool_settings.use_snap_project = True
bpy.context.scene.tool_settings.use_snap_rotate = True
bpy.context.scene.tool_settings.use_snap_scale = True
bpy.context.scene.tool_settings.use_mesh_automerge = True
bpy.context.scene.tool_settings.double_threshold = 0.01
Spivak Vladimir (cwolf3d)
committed
if context.scene.bsurfaces.SURFSK_guide == 'GPencil' and bs.SURFSK_gpencil == None:
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.ops.object.gpencil_add(radius=1.0, align='WORLD', location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), type='EMPTY')
bpy.context.scene.tool_settings.gpencil_stroke_placement_view3d = 'SURFACE'
gpencil_object = bpy.context.scene.objects[bpy.context.scene.objects[-1].name]
gpencil_object.select_set(True)
bpy.context.view_layer.objects.active = gpencil_object
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='PAINT_GPENCIL')
global_gpencil_object = gpencil_object.name
bpy.context.scene.bsurfaces.SURFSK_gpencil = bpy.data.objects[global_gpencil_object]
gpencil_object.data.stroke_depth_order = '3D'
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='PAINT_GPENCIL')
bpy.ops.wm.tool_set_by_id(name="builtin_brush.Draw")
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
if context.scene.bsurfaces.SURFSK_guide == 'Annotation':
bpy.ops.wm.tool_set_by_id(name="builtin.annotate")
bpy.context.scene.tool_settings.annotation_stroke_placement_view3d = 'SURFACE'
def invoke(self, context, event):
if bpy.context.active_object:
self.active_object = bpy.context.active_object
else:
self.active_object = None
Spivak Vladimir (cwolf3d)
committed
self.execute(context)
return {"FINISHED"}
Spivak Vladimir (cwolf3d)
committed
# ----------------------------
# Add modifiers operator
Spivak Vladimir (cwolf3d)
committed
class MESH_OT_SURFSK_add_modifiers(Operator):
bl_idname = "mesh.surfsk_add_modifiers"
bl_label = "Add Mirror and others modifiers"
Spivak Vladimir (cwolf3d)
committed
bl_description = "Add modifiers: Mirror, Shrinkwrap, Subdivision, Solidify"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
Spivak Vladimir (cwolf3d)
committed
bs = bpy.context.scene.bsurfaces
Spivak Vladimir (cwolf3d)
committed
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
if bs.SURFSK_mesh == None:
self.report({'ERROR_INVALID_INPUT'}, "Please select Mesh of BSurface or click Initialize")
else:
Spivak Vladimir (cwolf3d)
committed
mesh_object = bs.SURFSK_mesh
Spivak Vladimir (cwolf3d)
committed
try:
mesh_object.select_set(True)
except:
self.report({'ERROR_INVALID_INPUT'}, "Mesh of BSurface does not exist")
return {"CANCEL"}
Spivak Vladimir (cwolf3d)
committed
bpy.context.view_layer.objects.active = mesh_object
Spivak Vladimir (cwolf3d)
committed
try:
shrinkwrap = mesh_object.modifiers["Shrinkwrap"]
if self.active_object is not None and self.active_object != mesh_object:
shrinkwrap.target = self.active_object
shrinkwrap.wrap_method = 'TARGET_PROJECT'
shrinkwrap.wrap_mode = 'OUTSIDE_SURFACE'
Spivak Vladimir (cwolf3d)
committed
shrinkwrap.show_on_cage = True
shrinkwrap.offset = bpy.context.scene.bsurfaces.SURFSK_Shrinkwrap_offset
except:
bpy.ops.object.modifier_add(type='SHRINKWRAP')
shrinkwrap = mesh_object.modifiers["Shrinkwrap"]
if self.active_object is not None and self.active_object != mesh_object:
shrinkwrap.target = self.active_object
shrinkwrap.wrap_method = 'TARGET_PROJECT'
shrinkwrap.wrap_mode = 'OUTSIDE_SURFACE'
Spivak Vladimir (cwolf3d)
committed
shrinkwrap.show_on_cage = True
shrinkwrap.offset = bpy.context.scene.bsurfaces.SURFSK_Shrinkwrap_offset
Spivak Vladimir (cwolf3d)
committed
try:
mirror = mesh_object.modifiers["Mirror"]
mirror.use_clip = True
except:
bpy.ops.object.modifier_add(type='MIRROR')
mirror = mesh_object.modifiers["Mirror"]
mirror.use_clip = True
Spivak Vladimir (cwolf3d)
committed
_subsurf = mesh_object.modifiers["Subdivision"]
except:
bpy.ops.object.modifier_add(type='SUBSURF')
_subsurf = mesh_object.modifiers["Subdivision"]
Spivak Vladimir (cwolf3d)
committed
try:
solidify = mesh_object.modifiers["Solidify"]
solidify.thickness = 0.01
except:
bpy.ops.object.modifier_add(type='SOLIDIFY')
solidify = mesh_object.modifiers["Solidify"]
solidify.thickness = 0.01
return {"FINISHED"}
def invoke(self, context, event):
if bpy.context.active_object:
self.active_object = bpy.context.active_object
else:
self.active_object = None
self.execute(context)
return {"FINISHED"}
# ----------------------------
# Edit surface operator
Spivak Vladimir (cwolf3d)
committed
class MESH_OT_SURFSK_edit_surface(Operator):
bl_idname = "mesh.surfsk_edit_surface"
bl_label = "Bsurfaces edit surface"
bl_description = "Edit surface mesh"
Spivak Vladimir (cwolf3d)
committed
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
Spivak Vladimir (cwolf3d)
committed
bpy.context.scene.bsurfaces.SURFSK_mesh.select_set(True)
bpy.context.view_layer.objects.active = bpy.context.scene.bsurfaces.SURFSK_mesh
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='EDIT')
bpy.ops.wm.tool_set_by_id(name="builtin.select")
Spivak Vladimir (cwolf3d)
committed
def invoke(self, context, event):
try:
global_mesh_object = bpy.context.scene.bsurfaces.SURFSK_mesh.name
bpy.data.objects[global_mesh_object].select_set(True)
self.main_object = bpy.data.objects[global_mesh_object]
bpy.context.view_layer.objects.active = self.main_object
except:
self.report({'WARNING'}, "Specify the name of the object with retopology")
return{"CANCELLED"}
Spivak Vladimir (cwolf3d)
committed
self.execute(context)
return {"FINISHED"}
Spivak Vladimir (cwolf3d)
committed
# ----------------------------
# Add strokes operator
class GPENCIL_OT_SURFSK_add_strokes(Operator):
bl_idname = "gpencil.surfsk_add_strokes"
bl_label = "Bsurfaces add strokes"
bl_description = "Add the grease pencil strokes"
Spivak Vladimir (cwolf3d)
committed
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
Spivak Vladimir (cwolf3d)
committed
bpy.context.scene.bsurfaces.SURFSK_gpencil.select_set(True)
bpy.context.view_layer.objects.active = bpy.context.scene.bsurfaces.SURFSK_gpencil
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='PAINT_GPENCIL')
bpy.ops.wm.tool_set_by_id(name="builtin_brush.Draw")
Spivak Vladimir (cwolf3d)
committed
return{"FINISHED"}
def invoke(self, context, event):
bpy.context.scene.bsurfaces.SURFSK_gpencil.select_set(True)
except:
self.report({'WARNING'}, "Specify the name of the object with strokes")
return{"CANCELLED"}
Spivak Vladimir (cwolf3d)
committed
self.execute(context)
return {"FINISHED"}
# ----------------------------
# Edit strokes operator
class GPENCIL_OT_SURFSK_edit_strokes(Operator):
bl_idname = "gpencil.surfsk_edit_strokes"
bl_label = "Bsurfaces edit strokes"
bl_description = "Edit the grease pencil strokes"
Spivak Vladimir (cwolf3d)
committed
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
Spivak Vladimir (cwolf3d)
committed
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
Spivak Vladimir (cwolf3d)
committed
gpencil_object = bpy.context.scene.bsurfaces.SURFSK_gpencil
Spivak Vladimir (cwolf3d)
committed
gpencil_object.select_set(True)
bpy.context.view_layer.objects.active = gpencil_object
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='EDIT_GPENCIL')
Spivak Vladimir (cwolf3d)
committed
try:
bpy.ops.gpencil.select_all(action='SELECT')
except:
pass
def invoke(self, context, event):
try:
bpy.context.scene.bsurfaces.SURFSK_gpencil.select_set(True)
except:
self.report({'WARNING'}, "Specify the name of the object with strokes")
return{"CANCELLED"}
self.execute(context)
return {"FINISHED"}
# ----------------------------
Spivak Vladimir (cwolf3d)
committed
# Convert annotation to curves operator
class GPENCIL_OT_SURFSK_annotation_to_curves(Operator):
bl_idname = "gpencil.surfsk_annotations_to_curves"
bl_label = "Convert annotation to curves"
bl_description = "Convert annotation to curves for editing"
bl_options = {'REGISTER', 'UNDO'}
CoDEmanX
committed
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
Spivak Vladimir (cwolf3d)
committed
# Convert annotation to curve
curve = conver_gpencil_to_curve(self, context, None, 'Annotation')
CoDEmanX
committed
if curve != None:
# Delete annotation strokes
try:
bpy.context.annotation_data.layers.active.clear()
except:
pass
CoDEmanX
committed
# Clean up curves
curve.select_set(True)
bpy.context.view_layer.objects.active = curve
Spivak Vladimir (cwolf3d)
committed
bpy.ops.wm.tool_set_by_id(name="builtin.select_box")
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
return {"FINISHED"}
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
def invoke(self, context, event):
try:
strokes = bpy.context.annotation_data.layers.active.active_frame.strokes
Spivak Vladimir (cwolf3d)
committed
_strokes_num = len(strokes)
Spivak Vladimir (cwolf3d)
committed
except:
self.report({'WARNING'}, "Not active annotation")
return{"CANCELLED"}
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
self.execute(context)
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
return {"FINISHED"}
CoDEmanX
committed
Spivak Vladimir (cwolf3d)
committed
# ----------------------------
# Convert strokes to curves operator
class GPENCIL_OT_SURFSK_strokes_to_curves(Operator):
bl_idname = "gpencil.surfsk_strokes_to_curves"
bl_label = "Convert strokes to curves"
bl_description = "Convert grease pencil strokes to curves for editing"
bl_options = {'REGISTER', 'UNDO'}
Spivak Vladimir (cwolf3d)
committed
def execute(self, context):
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
Spivak Vladimir (cwolf3d)
committed
# Convert grease pencil strokes to curve
gp = bpy.context.scene.bsurfaces.SURFSK_gpencil
curve = conver_gpencil_to_curve(self, context, gp, 'GPensil')
Spivak Vladimir (cwolf3d)
committed
if curve != None:
# Delete grease pencil strokes
try:
bpy.context.scene.bsurfaces.SURFSK_gpencil.data.layers.active.clear()
except:
pass
Spivak Vladimir (cwolf3d)
committed
# Clean up curves
Spivak Vladimir (cwolf3d)
committed
curve.select_set(True)
bpy.context.view_layer.objects.active = curve
Spivak Vladimir (cwolf3d)
committed
bpy.ops.wm.tool_set_by_id(name="builtin.select_box")
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
return {"FINISHED"}
CoDEmanX
committed
bpy.context.scene.bsurfaces.SURFSK_gpencil.select_set(True)
except:
self.report({'WARNING'}, "Specify the name of the object with strokes")
return{"CANCELLED"}
CoDEmanX
committed
# ----------------------------
# Add annotation
class GPENCIL_OT_SURFSK_add_annotation(Operator):
bl_idname = "gpencil.surfsk_add_annotation"
bl_label = "Bsurfaces add annotation"
bl_description = "Add annotation"
Spivak Vladimir (cwolf3d)
committed
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
bpy.ops.wm.tool_set_by_id(name="builtin.annotate")
bpy.context.scene.tool_settings.annotation_stroke_placement_view3d = 'SURFACE'
return{"FINISHED"}
def invoke(self, context, event):
Spivak Vladimir (cwolf3d)
committed
self.execute(context)
return {"FINISHED"}
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
# ----------------------------
# Edit curve operator
Spivak Vladimir (cwolf3d)
committed
class CURVE_OT_SURFSK_edit_curve(Operator):
bl_idname = "curve.surfsk_edit_curve"
Spivak Vladimir (cwolf3d)
committed
bl_label = "Bsurfaces edit curve"
bl_description = "Edit curve"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='OBJECT')
Spivak Vladimir (cwolf3d)
committed
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.context.scene.bsurfaces.SURFSK_curve.select_set(True)
bpy.context.view_layer.objects.active = bpy.context.scene.bsurfaces.SURFSK_curve
bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='EDIT')
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
def invoke(self, context, event):
try:
bpy.context.scene.bsurfaces.SURFSK_curve.select_set(True)
except:
self.report({'WARNING'}, "Specify the name of the object with curve")
return{"CANCELLED"}
Spivak Vladimir (cwolf3d)
committed
Spivak Vladimir (cwolf3d)
committed
self.execute(context)
return {"FINISHED"}
# ----------------------------
# Reorder splines
class CURVE_OT_SURFSK_reorder_splines(Operator):
bl_idname = "curve.surfsk_reorder_splines"
bl_label = "Bsurfaces reorder splines"
bl_description = "Defines the order of the splines by using grease pencil strokes"
bl_options = {'REGISTER', 'UNDO'}
CoDEmanX
committed
def execute(self, context):
objects_to_delete = []
# Convert grease pencil strokes to curve.
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
bpy.ops.gpencil.convert('INVOKE_REGION_WIN', type='CURVE', use_link_strokes=False)
for ob in bpy.context.selected_objects:
if ob != bpy.context.view_layer.objects.active and ob.name.startswith("GP_Layer"):
GP_strokes_curve = ob
CoDEmanX
committed
# GP_strokes_curve = bpy.context.object
objects_to_delete.append(GP_strokes_curve)
CoDEmanX
committed
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.context.view_layer.objects.active = GP_strokes_curve
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
bpy.ops.curve.select_all('INVOKE_REGION_WIN', action='SELECT')
bpy.ops.curve.subdivide('INVOKE_REGION_WIN', number_cuts=100)
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
CoDEmanX
committed
bpy.ops.object.duplicate('INVOKE_REGION_WIN')
GP_strokes_mesh = bpy.context.object
objects_to_delete.append(GP_strokes_mesh)
CoDEmanX
committed
GP_strokes_mesh.data.resolution_u = 1
bpy.ops.object.convert(target='MESH', keep_original=False)
CoDEmanX
committed
bpy.ops.object.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.context.view_layer.objects.active = self.main_curve
CoDEmanX
committed
bpy.ops.object.duplicate('INVOKE_REGION_WIN')
curves_duplicate_1 = bpy.context.object
objects_to_delete.append(curves_duplicate_1)
CoDEmanX
committed
CoDEmanX
committed
# Some iterations since the subdivision operator
# has a limit of 100 subdivisions per iteration
for x in range(round(minimum_points_num / 100)):
# Check if the number of points of each curve has at least the number of points
# of minimum_points_num. If not, subdivide to reach at least that number of points
for i in range(len(curves_duplicate_1.data.splines)):
sp = curves_duplicate_1.data.splines[i]
CoDEmanX
committed
if len(sp.bezier_points) < minimum_points_num:
for bp in sp.bezier_points:
bp.select_control_point = True
CoDEmanX
committed
if (len(sp.bezier_points) - 1) != 0:
# Formula to get the number of cuts that will make a curve of N
# number of points have near to "minimum_points_num" points,
# when subdividing with this number of cuts
subdivide_cuts = int(
(minimum_points_num - len(sp.bezier_points)) /
(len(sp.bezier_points) - 1)
) + 1
CoDEmanX
committed
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
bpy.ops.curve.subdivide('INVOKE_REGION_WIN', number_cuts=subdivide_cuts)
bpy.ops.curve.select_all('INVOKE_REGION_WIN', action='DESELECT')
bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')