Skip to content

Instantly share code, notes, and snippets.

@carter2422
Last active December 19, 2015 01:49
Show Gist options
  • Save carter2422/5878358 to your computer and use it in GitHub Desktop.
Save carter2422/5878358 to your computer and use it in GitHub Desktop.
Quick Tools add-on
bl_info = {
"name": "Quick Tools",
"description": "A series of tools and menus to enhance and speed up workflow",
"author": "Jonathan Williamson",
"version": (0, 8),
"blender": (2, 6, 7),
"location": "View3D - 'Q' key gives a menu in Object, Edit, and Sculpt modes.",
"warning": '', # used for warning icon and text in addons panel
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/quicktools",
"tracker_url": "https://github.com/CGCookie/script-bakery/issues",
"category": "3D View"}
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'quicktools'))
if "bpy" in locals():
import imp
imp.reload(quick_operators)
imp.reload(quick_object_mode)
imp.reload(quick_edit_mode)
imp.reload(quick_sculpt_mode)
imp.reload(quick_mode_switch)
imp.reload(quick_scene)
print("Reloaded multifiles")
else:
from . import quick_operators, quick_object_mode, quick_edit_mode, quick_sculpt_mode, quick_mode_switch, quick_scene
print("Imported multifiles")
import quick_operators
import quick_object_mode
import quick_edit_mode
import quick_sculpt_mode
import quick_mode_switch
import quick_scene
import bpy
from bpy.props import StringProperty
from bpy.types import AddonPreferences
class QuickToolsPreferences(AddonPreferences):
bl_idname = __package__
scene_settings_key = StringProperty(
name="Scene Settings Key",
description="Set hotkey for Scene Settings menu",
default="`"
)
scene_settings_modifier_key = StringProperty(
name="Scene Settings Key",
description="Set modifier hotkey for Scene Settings menu",
default="SHIFT"
)
object_settings_key = StringProperty(
name="Object Settings Key",
description="Set hotkey for Object Settings menu",
default="`"
)
object_settings_modifier_key = StringProperty(
name="Object Settings Modifier Key",
description="Set modifier hotkey for Object Settings menu",
default="SHIFT"
)
object_mode_key = StringProperty(
name="Object Mode Key",
description="Set hotkey for Object Mode menu",
default="Q"
)
edit_mode_key = StringProperty(
name="Edit Mode Key",
description="Set hotkey for Edit Mode menu",
default="Q"
)
sculpt_mode_key = StringProperty(
name="Sculpt Mode Key",
description="Set hotkey for Sculpt Mode menu",
default="Q"
)
def draw(self, context):
layout = self.layout
split = layout.split()
col = split.column()
col.label(text="Global")
col.prop(self, "scene_settings_key")
col.prop(self, "object_settings_key")
col.prop(self, "scene_settings_modifier_key")
col.prop(self, "object_settings_modifier_key")
col = split.column(align=True)
col.label(text="Object Mode")
col.prop(self, "object_mode_key")
col.label(text="Edit Mode")
col.prop(self, "edit_mode_key")
col.label(text="Sculpt Mode")
col.prop(self, "sculpt_mode_key")
def register():
bpy.utils.register_class(QuickToolsPreferences)
quick_operators.register()
quick_object_mode.register()
quick_edit_mode.register()
quick_sculpt_mode.register()
quick_mode_switch.register()
quick_scene.register()
# bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_class(QuickToolsPreferences)
quick_operators.unregister()
quick_object_mode.unregister()
quick_edit_mode.unregister()
quick_sculpt_mode.unregister()
quick_mode_switch.unregister()
quick_scene.unregister()
#bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
import bpy
import os
from bpy import context
# creates a menu for edit mode tools
class QuickMeshTools(bpy.types.Menu):
bl_label = "Quick Mesh Tools"
bl_idname = "mesh.tools_menu"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("gpencil.surfsk_add_surface", 'Add BSurface', icon='OUTLINER_OB_SURFACE')
layout.operator("mesh.bridge_edge_loops")
layout.separator()
layout.operator("mesh.bevel")
layout.operator("mesh.inset").use_boundary=False
layout.operator("mesh.subdivide")
layout.separator()
layout.operator("mesh.knife_tool", icon='SCULPTMODE_HLT')
layout.operator("mesh.vert_connect")
layout.separator()
layout.operator("mesh.vertices_smooth")
layout.separator()
layout.operator("mesh.set_object_origin", "Origin to Selection")
layout.operator("object.mesh_halve", "Halve mesh")
layout.separator()
layout.operator("object.add_mirror", icon='MOD_MIRROR')
layout.operator("object.add_subsurf", 'Add Subsurf', icon='MOD_SUBSURF')
### ------------ New hotkeys and registration ------------ ###
addon_keymaps = []
def register():
#register the new menus
bpy.utils.register_class(QuickMeshTools)
wm = bpy.context.window_manager
# creatue the edit mode menu hotkey
km = wm.keyconfigs.addon.keymaps.new(name='Mesh')
kmi = km.keymap_items.new('wm.call_menu', 'Q', 'PRESS')
kmi.properties.name = 'mesh.tools_menu'
addon_keymaps.append(km)
def unregister():
#unregister the new menus
bpy.utils.unregister_class(QuickMeshTools)
# remove keymaps when add-on is deactivated
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
del addon_keymaps[:]
if __name__ == "__main__":
register()
import bpy
from bpy import context
# Create the operator that sets the mode
class SetMode(bpy.types.Operator):
bl_label = "Set Mode"
bl_idname = "object.working_mode"
setMode = bpy.props.StringProperty()
def execute(self, context):
bpy.ops.object.mode_set(mode=self.setMode)
return {"FINISHED"}
# adds a Mode switch menu
class ModeSwitch(bpy.types.Menu):
bl_label = "Quick Mode Switch Menu"
bl_idname = "mode.switch_menu"
def draw(self, context):
layout = self.layout
mode = bpy.context.object.mode
# check the current mode and only display the relavent modes, e.g. don't show current mode
if mode == 'EDIT' or mode == 'SCULPT' or mode == 'TEXTURE_PAINT' or mode == 'VERTEX_PAINT' or mode == 'WEIGHT_PAINT':
objectMode = layout.operator("object.working_mode", "Object Mode", icon="OBJECT_DATAMODE")
objectMode.setMode = 'OBJECT'
if mode == 'OBJECT' or mode == 'SCULPT' or mode == 'TEXTURE_PAINT' or mode == 'VERTEX_PAINT' or mode == 'WEIGHT_PAINT':
editMode = layout.operator("object.working_mode", "Edit Mode", icon="EDITMODE_HLT")
editMode.setMode = 'EDIT'
if mode == 'EDIT' or mode == 'OBJECT' or mode == 'TEXTURE_PAINT' or mode == 'VERTEX_PAINT' or mode == 'WEIGHT_PAINT':
sculptMode = layout.operator("object.working_mode", "Sculpt Mode", icon="SCULPTMODE_HLT" )
sculptMode.setMode = 'SCULPT'
if mode == 'EDIT' or mode == 'OBJECT' or mode == 'SCULPT' or mode == 'TEXTURE_PAINT' or mode == 'WEIGHT_PAINT':
sculptMode = layout.operator("object.working_mode", "Vertex Paint", icon="VPAINT_HLT" )
sculptMode.setMode = 'VERTEX_PAINT'
if mode == 'EDIT' or mode == 'OBJECT' or mode == 'SCULPT' or mode == 'TEXTURE_PAINT' or mode == 'VERTEX_PAINT':
sculptMode = layout.operator("object.working_mode", "Weight Paint", icon="WPAINT_HLT" )
sculptMode.setMode = 'WEIGHT_PAINT'
if mode == 'EDIT' or mode == 'OBJECT' or mode == 'SCULPT' or mode == 'VERTEX_PAINT' or mode == 'WEIGHT_PAINT':
sculptMode = layout.operator("object.working_mode", "Texture Paint", icon="TPAINT_HLT" )
sculptMode.setMode = 'TEXTURE_PAINT'
return {"FINISHED"}
addon_keymaps = []
def register():
bpy.utils.register_class(ModeSwitch)
bpy.utils.register_class(SetMode)
wm = bpy.context.window_manager
# create the mode switcher menu hotkey
km = wm.keyconfigs.addon.keymaps.new(name='3D View', space_type='VIEW_3D')
kmi = km.keymap_items.new('wm.call_menu', 'TAB', 'PRESS', alt=True)
kmi.properties.name = 'mode.switch_menu'
addon_keymaps.append(km)
def unregister():
bpy.utils.unregister_class(ModeSwitch)
bpy.utils.unregister_class(SetMode)
# remove keymaps when add-on is deactivated
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
del addon_keymaps[:]
if __name__ == "__main__":
register()
import bpy
import os
from bpy import context
# adds an object mode menu
class QuickObjectTools(bpy.types.Menu):
bl_label = "Quick Object Tools"
bl_idname = "object.tools_menu"
def draw(self, context):
layout = self.layout
layout.operator("object.add_subsurf", 'Add Subsurf', icon='MOD_SUBSURF')
layout.operator("object.apply_subsurf", 'Apply Subsurf')
#layout.operator("object.add_mirror", 'Add Mirror', icon='MOD_MIRROR')
#layout.operator("object.empty_add_unactive", "Add Target")
layout.separator()
layout.menu(SmartModifiers.bl_idname, "Add Smart Modifier", icon='MODIFIER')
layout.operator_menu_enum("object.modifier_add", "type")
layout.operator("object.apply_modifiers")
layout.operator("object.modifier_remove_all", "Remove All Modifiers")
layout.separator()
layout.operator("object.mesh_halve", "Halve and Mirror")
layout.separator()
layout.operator_menu_enum("object.origin_set", "type")
class SmartModifiers(bpy.types.Menu):
bl_idname = "object.smart_mod"
bl_label = "Smart Modifiers"
def draw (self, context):
layout = self.layout
layout.operator("object.empty_add_unactive", "Add Target", icon='CURSOR')
layout.separator()
layout.operator("object.add_array", "Array", icon='MOD_ARRAY')
layout.operator("object.add_boolean", "Boolean", icon='MOD_BOOLEAN')
layout.operator("object.add_mirror", "Mirror", icon='MOD_MIRROR')
layout.operator("object.add_lattice", "Lattice", icon='MOD_LATTICE')
layout.operator("object.add_screw", "Screw", icon='MOD_SCREW')
class QuickObjectOptions(bpy.types.Menu):
bl_idname = "object.display_options"
bl_label = "Quick Object Options"
def draw(self, context):
mode = bpy.context.object.mode
layout = self.layout
layout.operator("object.double_sided")
layout.operator("object.all_edges_wire")
layout.separator()
# add "Outline Selected" here.
if mode == 'OBJECT' or mode == 'SCULPT':
layout.operator("object.shade_smooth", icon='SOLID')
layout.operator("object.shade_flat", icon='MESH_UVSPHERE')
elif mode == 'EDIT':
layout.operator("mesh.faces_shade_smooth", icon='SOLID')
layout.operator("mesh.faces_shade_flat", icon='MESH_UVSPHERE')
### ------------ New hotkeys and registration ------------ ###
addon_keymaps = []
user_prefs = context.user_preferences
addon_prefs = user_prefs.addons['quicktools'].preferences
def register():
bpy.utils.register_module(__name__)
wm = bpy.context.window_manager
# create the object mode Quick Tools menu hotkey
km = wm.keyconfigs.addon.keymaps.new(name='Object Mode')
kmi = km.keymap_items.new('wm.call_menu', addon_prefs.object_mode_key, 'PRESS')
kmi.properties.name = 'object.tools_menu'
# create the object mode Display and Scene Tools menu hotkey
km = wm.keyconfigs.addon.keymaps.new(name='3D View')
kmi = km.keymap_items.new('wm.call_menu', 'Q', 'PRESS', shift=True)
kmi.properties.name = 'object.display_options'
addon_keymaps.append(km)
def unregister():
bpy.utils.unregister_module(__name__)
# remove keymaps when add-on is deactivated
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
del addon_keymaps[:]
if __name__ == "__main__":
register()
import bpy
from bpy import ops
###################################################
# Convienence variables
###################################################
applyModifier = ops.object.modifier_apply
### ------------ New Operators ------------ ###
###################################################
# Set object origin to center of current mesh selection in edit mdoe
###################################################
class setObjectOrigin(bpy.types.Operator):
"""Set Object Origin To Center Of Current Mesh Selection"""
bl_idname = "mesh.set_object_origin"
bl_label = "Set origin to the selection center"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
mode = bpy.context.object.mode
if mode != 'EDIT':
# If user is not in object mode, don't run the operator and report reason to the Info header
self.report({'INFO'}, "Must be run in Edit Mode")
else:
# Set the 3D Cursor to the selected mesh and then center the origin
# in object mode followed by returning to edit mode.
ops.view3d.snap_cursor_to_selected()
ops.object.mode_set(mode='OBJECT')
ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')
ops.object.mode_set(mode='EDIT')
return {"FINISHED"}
###################################################
# Add empty at cursor, making it inactively selected
###################################################
class addTarget(bpy.types.Operator):
"""Add an inactive, selected Empty Object as a modifier target"""
bl_label = "Add an unactive Empty Object"""
bl_idname = "object.empty_add_unactive"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
if len(context.selected_objects) > 0:
return True
return False
def execute(self, context):
scene = context.scene
activeObj = context.active_object
currentObj = activeObj
# Check to see if a target exists, if it does not then create one
selectedObj = context.selected_objects
for obj in selectedObj:
if obj.type == 'EMPTY':
break
elif obj.type != 'EMPTY':
ops.object.empty_add(type='PLAIN_AXES')
selectedObj = context.selected_objects
# Check if a smart modifier exists and assign the empty if necessary
### ---- dev note: this should all be combined into a reusable function. --- ###
for mod in currentObj.modifiers:
if mod.type == 'MIRROR':
for obj in selectedObj:
if obj.type == 'EMPTY':
mod.mirror_object = bpy.data.objects[obj.name]
obj.select = False
self.report({'INFO'}, "Assigned target object to existing modifier")
elif mod.type == 'ARRAY':
for obj in selectedObj:
if obj.type =='EMPTY':
mod.use_relative_offset = False
mod.use_object_offset = True
mod.offset_object = bpy.data.objects[obj.name]
self.report({'INFO'}, "Assigned target object to existing modifier")
elif mod.type == 'SCREW':
for obj in selectedObj:
if obj.type =='EMPTY':
mod.object = bpy.data.objects[obj.name]
self.report({'INFO'}, "Assigned target object to existing modifier")
# Select the previously stored current object and make it active
scene.objects.active = currentObj
currentObj.select = True
return {"FINISHED"}
###################################################
# Add a Subsurf Modifier at level 2 and optimal display enabled
###################################################
class addSubsurf(bpy.types.Operator):
"""Add a Subsurf modifier at level 2 with Optimal Display"""
bl_label = "Add a Subsurf Modifier"
bl_idname = "object.add_subsurf"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return len(context.selected_objects) > 0
def execute(self, context):
scene = context.scene
sel = context.selected_objects
for obj in sel:
scene.objects.active = obj
ops.object.modifier_add(type='SUBSURF')
print("Added Subsurf Modifier")
for mod in obj.modifiers:
if mod.type == 'SUBSURF':
mod.show_only_control_edges = True
mod.levels = 2
return {"FINISHED"}
###################################################
# Add Modifier function, for use with smart mod classes.
###################################################
def addMod(modifier):
ops.object.modifier_add(type=modifier)
return {"FINISHED"}
def checkObjects(target, type1, type2, modifier):
# Check for selected objects intended as target
for obj in bpy.context.selected_objects:
if obj.type == target:
useTarget = True
# Find all selected objects
for obj in bpy.context.selected_objects:
bpy.context.scene.objects.active = obj
if obj.type == target:
targetObj = obj
elif obj.type == type1 or obj.type == type2:
# Add a mirror modifier
addMod(modifier)
return {"FINISHED"}
############ Dev code to consolidate smart mods into a function #############
def assignTarget(modifier):
scene = bpy.context.scene
activeObj = bpy.context.active_object
targetObj = bpy.context.selected_objects
# Store the mesh object
selectedObj = activeObj
useTarget = False
if len(targetObj) > 1:
useTarget = True
# Make the targetObj active
try:
scene.objects.active = [obj for obj in targetObj if obj != activeObj][0]
except:
pass
# Check for active object
activeObj = bpy.context.active_object
# Swap the selected and active objects
selectedObj, activeObj = activeObj, selectedObj
# Deselect the target object and select the original mesh object again, making it active
selectedObj.select = False
activeObj.select = True
scene.objects.active = activeObj
# Find the added modifier, set the target object
for mod in activeObj.modifiers:
if mod.type == modifier:
if useTarget == True:
mod.object = bpy.data.objects[selectedObj.name]
return {"FINISHED"}
###################################################
# Add an Boolean modifier with second object as target
###################################################
class addBoolean(bpy.types.Operator):
"""Add a Boolean modifier with 2nd selected object as target object"""
bl_label = "Add Boolean Modifier"
bl_idname = "object.add_boolean"
bl_options = {'REGISTER', 'UNDO'}
# Check to see if an object is selected
@classmethod
def poll(cls, context):
return len(context.selected_objects) > 0
# Add the modifier
def execute(self, context):
scene = bpy.context.scene
activeObj = context.active_object
targetObj = context.selected_objects
addMod("BOOLEAN")
assignTarget("BOOLEAN")
self.report({'INFO'}, "Assigned second object to modifier")
return {"FINISHED"}
###################################################
# Add a Mirror Modifier with clipping enabled
###################################################
class addMirror(bpy.types.Operator):
"""Add a Mirror modifier with clipping, use 2nd selected object as Mirror center"""
bl_label = "Add Mirror Modifier"
bl_idname = "object.add_mirror"
bl_options = {'REGISTER', 'UNDO'}
# Check to see if an object is selected
@classmethod
def poll(cls, context):
return len(context.selected_objects) > 0
# Add the modifier
def execute(self, context):
scene = context.scene
# Check for active object
activeObj = context.active_object
selected = context.selected_objects
# Store the mesh object
origActive = activeObj
# Set status of mirror object usage
useTarget = False
#### not yet functional ####
# checkObjects('EMPTY', 'MESH', 'CURVE', 'MIRROR')
# If no Empty is selected, don't use mirror object
for obj in context.selected_objects:
if obj.type == 'EMPTY':
useMirrorObj = True
# Find all selected objects
for obj in context.selected_objects:
scene.objects.active = obj
if obj.type == 'EMPTY':
targetObj = obj
elif obj.type == 'MESH' or obj.type == 'CURVE':
# Add a mirror modifier
addMod("MIRROR")
#Make the targetObj active
try:
scene.objects.active = [obj for obj in targetObj if obj != activeObj][0]
except:
pass
# Check for active object
activeObj = context.active_object
# Swap the selected and active objects
origActive, activeObj = activeObj, origActive
# Deselect the empty object and select the mesh object again, making it active
origActive.select = False
activeObj.select = True
scene.objects.active = activeObj
for obj in selected:
scene.objects.active = obj
# Find the added modifier, enable clipping, set the mirror object
for mod in obj.modifiers:
if mod.type == 'MIRROR':
mod.use_clip = True
if useTarget:
mod.mirror_object = bpy.data.objects[targetObj.name]
self.report({'INFO'}, "Assigned target object to modifier")
return {"FINISHED"}
###################################################
# Add a Lattice with auto assigning of the lattice object
###################################################
class addLattice(bpy.types.Operator):
"""Add a Lattice Modifier and auto-assign to selected lattice object"""
bl_idname = "object.add_lattice"
bl_label = "Add a lattice modifier"
bl_options = {'REGISTER', 'UNDO'}
# Check to see if an object is selected
@classmethod
def poll(cls, context):
return len(context.selected_objects) > 0
# Add the modifier
def execute(self, context):
scene = bpy.context.scene
activeObj = context.active_object
targetObj = context.selected_objects
# Add a lattice modifier
addMod("LATTICE")
# Store the mesh object
selectedObj = activeObj
# Set status of lattice object usage
useLatticeObj = False
# If an second object is not selected, don't use lattice object
if len(targetObj) > 1:
useLatticeObj = True
# Make the targetObj active
try:
scene.objects.active = [obj for obj in targetObj if obj != activeObj][0]
except:
pass
# Check for active object
activeObj = context.active_object
# Swap the selected and active objects
selectedObj, activeObj = activeObj, selectedObj
# Deselect the empty object and select the mesh object again, making it active
selectedObj.select = False
activeObj.select = True
scene.objects.active = activeObj
# Find the added modifier, set the lattice object
for mod in activeObj.modifiers:
if mod.type == 'LATTICE':
if useLatticeObj == True:
mod.object = bpy.data.objects[selectedObj.name]
self.report({'INFO'}, "Assigned lattice object to modifier")
return {"FINISHED"}
###################################################
# Add an Array modifier with object offset enabled
###################################################
class addArray(bpy.types.Operator):
"""Add a Array modifier with object offset, use 2nd selected object as offset object"""
bl_label = "Add Array Modifier"
bl_idname = "object.add_array"
bl_options = {'REGISTER', 'UNDO'}
# Check to see if an object is selected
@classmethod
def poll(cls, context):
return len(context.selected_objects) > 0
# Add the modifier
def execute(self, context):
scene = bpy.context.scene
activeObj = context.active_object
targetObj = context.selected_objects
# Add a array modifier
addMod("ARRAY")
# Store the mesh object
selectedObj = activeObj
# Set status of array object usage
useArrayObj = False
# If a second object is not selected, don't use mirror object
if len(targetObj) > 1:
useArrayObj = True
# Make the targetObj active
try:
scene.objects.active = [obj for obj in targetObj if obj != activeObj][0]
except:
pass
# Check for active object
activeObj = context.active_object
# Swap the selected and active objects
selectedObj, activeObj = activeObj, selectedObj
# Deselect the empty object and select the mesh object again, making it active
selectedObj.select = False
activeObj.select = True
scene.objects.active = activeObj
# Find the added modifier, and check for status of useArrayObj
if useArrayObj == True:
for mod in activeObj.modifiers:
if mod.type == 'ARRAY':
mod.use_relative_offset = False
mod.use_object_offset = True
if useArrayObj:
mod.offset_object = bpy.data.objects[selectedObj.name]
self.report({'INFO'}, "Assigned target object to modifier")
return {"FINISHED"}
###################################################
# Add a Screw modifier with an object axis set
###################################################
class addScrew(bpy.types.Operator):
"""Add a Screw modifier, use 2nd selected object as object axis"""
bl_label = "Add Screw Modifier"
bl_idname = "object.add_screw"
bl_options = {'REGISTER', 'UNDO'}
# Check to see if an object is selected
@classmethod
def poll(cls, context):
return len(context.selected_objects) > 0
# Add the modifier
def execute(self, context):
scene = context.scene
# Check for active object
activeObj = context.active_object
# Find all selected objects
targetObj = context.selected_objects
# Add a screw modifier
addMod("SCREW")
# Store the mesh object
selectedObj = activeObj
# Set status of screw object usage
useScrewObj = False
# If a second object is not selected, don't use screw object
if len(targetObj) > 1:
useScrewObj = True
# Make the targetObj active
try:
scene.objects.active = [obj for obj in targetObj if obj != activeObj][0]
except:
pass
# Check for active object
activeObj = context.active_object
# Swap the selected and active objects
(selectedObj, activeObj) = (activeObj, selectedObj)
# Deselect the empty object and select the mesh object again, making it active
selectedObj.select = False
activeObj.select = True
scene.objects.active = activeObj
# Find the added modifier, enable clipping, set the mirror object
for mod in activeObj.modifiers:
if mod.type == 'SCREW':
if useScrewObj == True:
mod.object = bpy.data.objects[selectedObj.name]
self.report({'INFO'}, "Assigned target axis object to modifier")
return {"FINISHED"}
###################################################
# Halve the mesh and add a Mirror modifier
###################################################
def halve_mesh(self, context):
obj = context.active_object.data
for verts in obj.vertices:
if verts.co.x < -0.001:
verts.select = True
class halveMesh(bpy.types.Operator):
"""Delete all vertices on the -X side of center"""
bl_idname = "object.mesh_halve"
bl_label = "Halve and mirror mesh"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
if bpy.context.active_object.type == 'MESH':
return True
return False
def execute(self, context):
obj = context.active_object.data
selected = context.selected_objects
# Go to edit mode and ensure all vertices are deselected, preventing accidental deletions
if context.object.mode == 'OBJECT':
for obj in selected:
if obj.type == 'MESH':
context.scene.objects.active = obj
ops.object.mode_set(mode='EDIT')
ops.mesh.select_all(action='DESELECT')
ops.object.mode_set(mode='OBJECT')
# Find verts left of center and select them
halve_mesh(self, context)
# for verts in obj.vertices:
# if verts.co.x < -0.001:
# verts.select = True
# Toggle edit mode and delete the selection
ops.object.mode_set(mode='EDIT')
ops.mesh.delete(type='VERT')
# Switch back to object mode and add the mirror modifier
ops.object.mode_set(mode='OBJECT')
addMod("MIRROR")
self.report({'INFO'}, "Mesh half removed and Mirror modifier added")
else:
self.report({'INFO'}, "Only works on mesh objects")
elif bpy.context.object.mode == 'EDIT':
ops.mesh.select_all(action='DESELECT')
ops.object.mode_set(mode='OBJECT')
# Find verts left of center and select them
halve_mesh(self, context)
# Toggle edit mode and delete the selection
ops.object.mode_set(mode='EDIT')
ops.mesh.delete(type='VERT')
self.report({'INFO'}, "Mesh half removed")
return {'FINISHED'}
###################################################
# Apply only subsurf modifiers
###################################################
class applySubsurf(bpy.types.Operator):
"""Apply only Subsurf Modifiers"""
bl_label = "Apply Only Subsurf Modifiers"
bl_idname = "object.apply_subsurf"
bl_options = {'REGISTER', 'UNDO'}
# Test if it is possible to apply a subsurf modifier, thanks to Richard Van Der Oost
@classmethod
def poll(cls, context):
# Get the active object
obj = context.active_object
# Test if there's an active object
if obj:
# Find modifiers with "SUBSURF" type
for mod in obj.modifiers:
if mod.type == 'SUBSURF':
return True
return False
def execute(self, context):
#check for active object
obj = context.active_object
# If any subsurf modifiers exist on object, apply them.
for mod in obj.modifiers:
if mod.type == 'SUBSURF':
applyModifier(apply_as='DATA', modifier=mod.name)
self.report({'INFO'}, "Applied Subsurf modifier(s)")
return {"FINISHED"}
###################################################
# Add a Remesh Modifier with Smooth set as the type
###################################################
class addRemesh(bpy.types.Operator):
"""Add a Smooth Remesh Modifier"""
bl_label = "Smooth Remesh"
bl_idname = "object.smooth_remesh"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
#
return not context.sculpt_object.use_dynamic_topology_sculpting
def execute(self, context):
ops.object.modifier_add(type='REMESH')
context.object.modifiers['Remesh'].mode = 'SMOOTH'
return {"FINISHED"}
###################################################
# Apply any remesh modifiers
###################################################
class applyRemesh(bpy.types.Operator):
"""Apply only Remesh Modifiers"""
bl_label = "Apply Only Remesh Modifiers"
bl_idname = "object.apply_remesh"
bl_options = {'REGISTER', 'UNDO'}
# test if it is possible to apply a remesh modifier
@classmethod
def poll(cls, context):
# get the active object
obj = context.active_object
# test if there's an active object
if obj:
# find modifiers with "REMESH" type
for mod in obj.modifiers:
if mod.type == 'REMESH':
return True
return False
def execute(self, context):
#check for active object
obj = context.active_object
# If any remesh modifiers exist on object, apply them.
for mod in obj.modifiers:
if mod.type == 'REMESH':
applyModifier(apply_as='DATA', modifier=mod.name)
self.report({'INFO'}, "Applied remesh modifier(s)")
return {"FINISHED"}
###################################################
# Apply all modifiers on the active object
###################################################
class applyModifiers(bpy.types.Operator):
"""Apply all modifiers on selected objects"""
bl_label = "Apply All Modifiers"
bl_idname = "object.apply_modifiers"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
# Make sure there's a selected object and that that object has modifiers to apply
return len(context.selected_objects) > 0 and len(context.active_object.modifiers) > 0
def execute(self, context):
sel = context.selected_objects
for obj in sel:
# set the current object in the loop to active
context.scene.objects.active = obj
# If any modifiers exist on current object object, apply them.
for mod in obj.modifiers:
applyModifier(apply_as='DATA', modifier=mod.name)
# maybe for debug you might do an 'applied to obj.name' in before
# iterating to the next
self.report({'INFO'}, "Applied all modifiers on selected objects")
return {"FINISHED"}
###################################################
# Remove all modifiers on selected objects
###################################################
class removeModifiers(bpy.types.Operator):
"""Remove Modifiers From Selected Objects"""
bl_idname = "object.modifier_remove_all"
bl_label = "Remove modifiers on all selected objects"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return len(context.selected_objects) > 0
def execute(self, context):
selected = context.selected_objects
for obj in selected:
context.scene.objects.active = obj
for mod in obj.modifiers:
ops.object.modifier_remove(modifier=mod.name)
self.report({'INFO'}, "Removed all modifiers on selected objects")
return {'FINISHED'}
###################################################
# Creating operator for toggling Sculpt Symmetry
###################################################
class sculptSymmetry(bpy.types.Operator):
"""Toggle Symmetry For Sculpting"""
bl_idname = "sculpt.symmetry"
bl_label = "Toggle Sculpt Symmetry"
axis = bpy.props.IntProperty(name = "Axis",
description = "switch between symmetry axis'",
default = 0)
def execute(self, context):
if self.axis == -1:
symmetry_x = context.tool_settings.sculpt.use_symmetry_x
context.tool_settings.sculpt.use_symmetry_x = not symmetry_x
if self.axis == 0:
symmetry_y = context.tool_settings.sculpt.use_symmetry_y
context.tool_settings.sculpt.use_symmetry_y = not symmetry_y
if self.axis == 1:
symmetry_z = context.tool_settings.sculpt.use_symmetry_z
context.tool_settings.sculpt.use_symmetry_z = not symmetry_z
return {"FINISHED"}
###################################################
# Creating operator for toggling Axis Locks
###################################################
class sculptAxisLock(bpy.types.Operator):
"""Toggle Axis Lock In Sculpting"""
bl_idname = "sculpt.axislock"
bl_label = "Toggle Axis Lock"
axis = bpy.props.IntProperty(name = "Axis",
description = "switch axis' to lock",
default = 0)
def execute(self, context):
if self.axis == -1:
lock_x = context.tool_settings.sculpt.lock_x
context.tool_settings.sculpt.lock_x = not lock_x
if self.axis == 0:
lock_y = context.tool_settings.sculpt.lock_y
context.tool_settings.sculpt.lock_y = not lock_y
if self.axis == 1:
lock_z = context.tool_settings.sculpt.lock_z
context.tool_settings.sculpt.lock_z = not lock_z
return {"FINISHED"}
###################################################
# Creating operator for toggling collapse short edges
###################################################
class sculptCollapseShortEdges(bpy.types.Operator):
""""Toggle Collapse Short Edges Option"""
bl_label = "Toggle Collapse Short Edges"
bl_idname = "sculpt.collapse_short_edges"
# test if it is possible to toggle short edge collapse
@classmethod
def poll(cls, context):
# if dyntopo True, returns True, else returns False :)
return context.sculpt_object.use_dynamic_topology_sculpting
def execute(self, context):
#invert current state
shortEdges = context.scene.tool_settings.sculpt.use_edge_collapse
context.scene.tool_settings.sculpt.use_edge_collapse = not shortEdges
return {"FINISHED"}
###################################################
# Creating operator for toggling double sided
###################################################
class objectDoubleSided(bpy.types.Operator):
"""Toggle Double Sided Option"""
bl_label = "Toggle Double Sided"
bl_idname = "object.double_sided"
bl_description = "Toggle double-sided on all selected objects"
def execute(self, context):
scene = context.scene
selected = context.selected_objects
origActive = context.active_object
doubleSided = context.object.data.show_double_sided
for obj in selected:
scene.objects.active = obj
context.object.data.show_double_sided = not doubleSided
scene.objects.active = origActive
return {"FINISHED"}
###################################################
# Creating operator for toggling all edges wire
###################################################
class allEdgesWire(bpy.types.Operator):
"""Toggle Wire Display With All Edges"""
bl_label = "Toggle All Edges Wire"
bl_idname = "object.all_edges_wire"
bl_description = "Toggle all-edges wireframe on all selected objects"
def execute(self, context):
scene = context.scene
selected = context.selected_objects
origActive = context.active_object
allEdges = context.object.show_all_edges
wire = context.object.show_wire
for obj in selected:
scene.objects.active = obj
context.object.show_all_edges = not allEdges
context.object.show_wire = not wire
scene.objects.active = origActive
return {"FINISHED"}
# boiler plate: register / unregister
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
import bpy
class QuickSceneOptions(bpy.types.Menu):
bl_idname = "scene.quick_options"
bl_label = "Quick Scene Settings"
def draw(self, context):
layout = self.layout
layout.operator("gpencil.active_frame_delete", "Delete Grease", icon='GREASEPENCIL')
addon_keymaps = []
def register():
bpy.utils.register_class(QuickSceneOptions)
wm = bpy.context.window_manager
# create the Scene Tools menu hotkey
km = wm.keyconfigs.addon.keymaps.new(name='3D View', space_type='VIEW_3D')
kmi = km.keymap_items.new('wm.call_menu', 'ACCENT_GRAVE', 'PRESS', shift=True)
kmi.properties.name = 'scene.quick_options'
addon_keymaps.append(km)
def unregister():
bpy.utils.unregister_class(QuickSceneOptions)
# remove keymaps when add-on is deactivated
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
del addon_keymaps[:]
if __name__ == "__main__":
register()
import bpy
### ------------ New Menus ------------ ###
# creates a menu for Sculpt mode tools
class QuickSculptTools(bpy.types.Menu):
bl_label = "Quick Sculpt Tools"
bl_idname = "sculpt.tools_menu"
def draw(self, context):
layout = self.layout
dyntopo = bpy.context.sculpt_object.use_dynamic_topology_sculpting
shortEdges = bpy.context.scene.tool_settings.sculpt.use_edge_collapse
symmetry_x = bpy.context.tool_settings.sculpt.use_symmetry_x
symmetry_y = bpy.context.tool_settings.sculpt.use_symmetry_y
symmetry_z = bpy.context.tool_settings.sculpt.use_symmetry_z
lock_x = bpy.context.tool_settings.sculpt.lock_x
lock_y = bpy.context.tool_settings.sculpt.lock_y
lock_z = bpy.context.tool_settings.sculpt.lock_z
if dyntopo:
layout.operator("sculpt.dynamic_topology_toggle", 'Disable Dynamic Topology',)
else:
layout.operator("sculpt.dynamic_topology_toggle", 'Enable Dynamic Topology')
if shortEdges:
layout.operator("sculpt.collapse_short_edges", 'Disable Collapse Short Edges',)
else:
layout.operator("sculpt.collapse_short_edges", 'Enable Collpase Short Edges')
layout.separator()
layout.operator("object.add_subsurf", 'Add Subsurf', icon='MOD_SUBSURF')
layout.operator("object.apply_subsurf", 'Apply Subsurf')
layout.separator()
layout.operator("object.smooth_remesh", 'Remesh Modifier', icon='MOD_REMESH')
layout.operator("object.apply_remesh", 'Apply Remesh')
layout.separator()
layout.operator("object.apply_modifiers", 'Apply All Modifiers')
layout.separator()
if symmetry_x:
layout.operator("sculpt.symmetry", 'Disable X Symmetry').axis = -1
else:
layout.operator("sculpt.symmetry", 'Enable X Symmetry').axis = -1
if symmetry_y:
layout.operator("sculpt.symmetry", 'Disable Y Symmetry').axis = 0
else:
layout.operator("sculpt.symmetry", 'Enable Y Symmetry').axis = 0
if symmetry_z:
layout.operator("sculpt.symmetry", 'Disable Z Symmetry').axis = 1
else:
layout.operator("sculpt.symmetry", 'Enable Z Symmetry').axis = 1
layout.separator()
if lock_x:
layout.operator("sculpt.axislock", 'Disable X Lock', icon='MANIPUL').axis = -1
else:
layout.operator("sculpt.axislock", 'Enable X Lock', icon='MANIPUL').axis = -1
if lock_y:
layout.operator("sculpt.axislock", 'Disable Y Lock').axis = 0
else:
layout.operator("sculpt.axislock", 'Enable Y Lock').axis = 0
if lock_z:
layout.operator("sculpt.axislock", 'Disable Z Lock').axis = 1
else:
layout.operator("sculpt.axislock", 'Enable Z Lock').axis = 1
### ------------ New Hotkeys and registration ------------ ###
addon_keymaps = []
def register():
bpy.utils.register_class(QuickSculptTools)
wm = bpy.context.window_manager
# create the Sculpt hotkeys
km = wm.keyconfigs.addon.keymaps.new(name='Sculpt')
# km = bpy.context.window_manager.keyconfigs.active.keymaps['Sculpt']
kmi = km.keymap_items.new('sculpt.symmetry', 'X', 'PRESS', shift=True)
kmi.properties.axis = -1
kmi = km.keymap_items.new('sculpt.symmetry', 'Y', 'PRESS', shift=True)
kmi.properties.axis = 0
kmi = km.keymap_items.new('sculpt.symmetry', 'Z', 'PRESS', shift=True)
kmi.properties.axis = 1
# create sculpt menu hotkey
kmi = km.keymap_items.new('wm.call_menu', 'Q', 'PRESS')
kmi.properties.name = 'sculpt.tools_menu'
addon_keymaps.append(km)
def unregister():
#unregister the new operators
bpy.utils.unregister_class(QuickSculptTools)
# remove keymaps when add-on is deactivated
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
del addon_keymaps[:]
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment