Last active
December 19, 2015 01:49
-
-
Save carter2422/5878358 to your computer and use it in GitHub Desktop.
Quick Tools add-on
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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