Hey Guys, I have been playing around with blender and some scripting lately. I decided to port Pedro's excellent
super smart create scriptI am really new to Blender and my python coding skills are not the finest, so please if you find any better way to do stuff or if i'm making any stupid shit just let me know.
Anyways, here's the tool (the descriptions are taken from Pedro's thread, so you can compare the functionality).
Connects verts that belong to the same face
If you select one vert or two verts that share the same edge and are on a border it will invoke f2(make sure you have f2 enabled):
Divides the selected edge in 2, putting a vert in the middle of the edge
Connects the selected edges if there is faces in between the edges
Caps selected borders
Bridges selected edges if possible
When you select 2 adjacent edges it creates a face
Bridges selected polys
Heres an extra one, tries to make quads from a selected face.
This last feature works pretty good if you cap a border and then run the script again to make quads out of it:
Installation:
Pretty much the standard blender plugin installation. Load it up from the install from file option in user Preferences and make sure you enable it.
You can either run it from the mesh-> Super Smart Create menu or assign a hotkey to it. Id recommend you to assign a hotkey to it, to make it even easier to use. To assign a hotkey you can find it in Input -> 3D View- > Mesh -> Super Smart Create
I have developed it in Blender 2.78c, so no idea if it works with older versions or not
Download(save this as a .py file):
bl_info = {
"name": "Super Smart Create",
"author": "Maximiliano Vazquez, Original idea: Pedro Amorim",
"version": (1, 0),
"blender": (2, 65, 0),
"location": "Mesh > Super Smart Create",
"description": "Context Sensitive mesh modification",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Mesh"}
import bpy
import bmesh
from bpy.types import Operator, AddonPreferences
from bpy.props import StringProperty
import mesh_f2
#Global Variables
ITERATION_LIMIT = 200
#Functions
def list_intersection(a, b):
return list(set(a) & set(b))
def list_difference(a,b):
return list(set(a)- set(b))
def get_bmesh():
return bmesh.from_edit_mesh(bpy.context.edit_object.data)
def update_indexes(bm ,verts=False, edges=False, faces=False):
if verts:
bm.verts.index_update()
if edges:
bm.edges.index_update()
if faces:
bm.faces.index_update()
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
bm.faces.ensure_lookup_table()
bmesh.update_edit_mesh(bpy.context.edit_object.data)
return bm
def get_selected(bm,verts=False, edges = False, faces = False, get_item = False):
if verts:
bm = update_indexes(bm, verts=True)
selected_verts = []
for vert in bm.verts:
if vert.select :
if get_item:
selected_verts.append(vert)
else:
selected_verts.append(vert.index)
return selected_verts
if edges:
bm = update_indexes(bm,edges=True)
selected_edges = []
for edge in bm.edges:
if edge.select:
if get_item:
selected_edges.append(edge)
else:
selected_edges.append(edge.index)
return selected_edges
if faces:
bm = update_indexes(bm,faces=True)
selected_faces = []
for face in bm.faces:
if face.select:
if get_item:
selected_faces.append(face)
else:
selected_faces.append(face.index)
return selected_faces
def select_from_index(bm,indexes, verts = False,edges = False, faces = False, replace = False, add_to_history = False):
if replace:
bpy.ops.mesh.select_all(action='DESELECT')
if verts:
for index in indexes:
bm.verts[index].select = True
if add_to_history:
bm.select_history.add(bm.verts[index])
if edges:
for index in indexes:
bm.edges[index].select = True
if add_to_history:
bm.select_history.add(bm.edges[index])
if faces:
for index in indexes:
bm.faces[index].select = True
if add_to_history:
bm.select_history.add(bm.faces[index])
def select_from_item(bm,items, verts = False,edges = False, faces = False, replace = False, add_to_history = False):
if replace:
bpy.ops.mesh.select_all(action='DESELECT')
if verts:
for item in items:
bm.verts[item.index].select = True
if add_to_history:
bm.select_history.add(bm.verts[item.index])
if edges:
for item in items:
bm.edges[item.index].select = True
if add_to_history:
bm.select_history.add(bm.edges[item.index])
if faces:
for item in items:
bm.faces[item.index].select = True
if add_to_history:
bm.select_history.add(bm.faces[item.index])
def verts_share_edge(bm):
other_verts = []
verts = get_selected(bm,verts = True, get_item = True)
for vert in verts:
for edge in vert.link_edges:
other_vert = edge.other_vert(vert)
other_verts.append(other_vert)
return vert in other_verts
def is_border(bm):
edge_list = get_selected(bm,edges = True, get_item = True)
select_from_index(bm,[edge_list[0].index],edges = True, replace = True)
bpy.ops.mesh.loop_multi_select(ring=False)
border_selection = get_selected(bm, edges = True, get_item = True)
border_edges = all(len((edge.link_faces)) is 1 for edge in edge_list)
is_complete_border = all(edge in edge_list for edge in border_selection)
select_from_item(bm,edge_list,edges = True, replace = True)
return border_edges and is_complete_border
def is_adjacent(bm):
edge_list = get_selected(bm,edges = True)
select_from_index(bm,[edge_list[0]],edges = True, replace = True)
bpy.ops.mesh.select_more()
new_selection = get_selected(bm, edges = True)
select_from_index(bm,edge_list,edges = True, replace = True)
return all(edge in new_selection for edge in edge_list)
def is_ring(bm):
selection = get_selected(bm,edges = True, get_item = True)
result = all(len((edge.link_faces)) is 2 for edge in selection)
return result
def split_edge_select_vert(bm, change_selection = False):
selection = get_selected(bm,verts = True)
bpy.ops.mesh.subdivide()
new_selection = get_selected(bm,verts = True)
new_selection = list_difference(new_selection, selection)
if change_selection:
select_from_index(bm,new_selection, verts = True,replace = True)
bpy.context.scene.tool_settings.mesh_select_mode = [True,False,False]
return new_selection
def are_border_verts(bm, selection):
selection = get_selected(bm,verts = True)
return all(len(bm.verts[vert].link_faces) <= 3 for vert in selection)
def quad_fill(bm):
selection = get_selected(bm,edges = True)
bpy.ops.mesh.delete(type='FACE')
select_from_index(bm,selection, edges = True,replace = True)
bpy.ops.mesh.fill_grid()
def super_smart_create():
bm = get_bmesh()
selectionMode = (tuple(bpy.context.scene.tool_settings.mesh_select_mode))
#if Vertex is selected
if selectionMode[0]:
selection = get_selected(bm,verts = True)
if len(selection) == 1 or (verts_share_edge(bm) and are_border_verts(bm,selection)):
print(are_border_verts(bm,selection))
mesh_f2.bpy.ops.mesh.f2('INVOKE_DEFAULT')
else:
bpy.ops.mesh.vert_connect()
#if Edge is selected
elif selectionMode[1]:
selection = get_selected(bm,edges = True)
if len(selection) == 1:
split_edge_select_vert(bm,change_selection = True)
elif is_border(bm):
bpy.ops.mesh.edge_face_add()
bpy.context.scene.tool_settings.mesh_select_mode = [False,False,True]
elif is_ring(bm):
bpy.ops.mesh.subdivide(number_cuts = 1, quadcorner = 'INNERVERT')
bpy.ops.mesh.select_less()
elif is_adjacent(bm):
bpy.ops.mesh.edge_face_add()
bpy.context.scene.tool_settings.mesh_select_mode = [False,True,False]
else:
bpy.ops.mesh.bridge_edge_loops()
bpy.context.scene.tool_settings.mesh_select_mode = [False,True, False]
#if Face is selected
elif selectionMode[2]:
selection = get_selected(bm,faces = True)
if len(selection) == 1:
quad_fill(bm)
if len(selection) > 1:
bpy.ops.mesh.bridge_edge_loops()
#bm.free()
class SuperSmartCreate(bpy.types.Operator):
""" Super Smart Create"""
bl_idname = "mesh.super_smart_create"
bl_label = "Super Smart Create"
bl_options = {'REGISTER', 'UNDO'}
def execute(self,context):
super_smart_create()
return {'FINISHED'}
class SuperSmartCreatePreferences(bpy.types.AddonPreferences):
bl_idname = __name__
assigned_hotkey = StringProperty(
name="Assigned Hotkey",
default = 'NONE',
)
def draw(self, context):
layout = self.layout
layout.prop(self,assigned_hotkey)
def SuperSmartCreatePrefs_Menu(self, context):
self.layout.operator(SuperSmartCreate.bl_idname)
# store keymaps here to access after registration
addon_keymaps = []
def register():
bpy.utils.register_class(SuperSmartCreate)
#Make menu
bpy.types.VIEW3D_MT_edit_mesh.append(SuperSmartCreatePrefs_Menu)
##Handle Keymap
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Mesh', space_type='EMPTY')
kmi = km.keymap_items.new(SuperSmartCreate.bl_idname, 'W', 'PRESS', alt = True)
addon_keymaps.append((km, kmi))
def unregister():
bpy.utils.unregister_class(SuperSmartCreate)
#bpy.utils.unregister_class(SuperSmartCreatePreferences)
#Remove Menu
bpy.types.VIEW3D_MT_edit_mesh.remove(SuperSmartCreatePrefs_Menu)
#Remove Keymaps
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
addon_keymaps.clear()
if __name__ == "__main__":
register()
Please report any problems, suggestions, so I can *hopefully* improve it . Hope you guys find it useful.
Replies
I can't say though, that it seems like a huge timesaver from my perspective, but it's certainly might be useful for some.
are you going to implement completely new features as well as porting those from the other script?
i had my own little script that had a few things combined but not as many as in this one.
so thanks
Thanks for the report @huffer!
I have updated the script in the main post. Please use the updated version to avoid this problem.
@thomasp Probablly not more than the extra 2 I have added, but if you have any ideas please let me know and I will see what I can do to implement them
do you think you could add "cut faces" for when polygons next to each other are selected (to not interfere with the bridge tool)
http://blenderaddonlist.blogspot.de/2015/01/addon-cut-faces.html
I think I have a version of Pedro's Super Smart Create in almost every piece of software I work with now
There's another new thread with his latest updates that should work on 2.8. I think this is a bit of an older one.