Add Easy_Weight
to Addons
#47
21
README.md
21
README.md
@ -1,19 +1,9 @@
|
|||||||
Easy Weight is an addon focused on quality of life improvements for weight painting in Blender.
|
Easy Weight is an addon focused on quality of life improvements for weight painting in Blender.
|
||||||
|
|
||||||
### Brush Switching
|
|
||||||
The addon will force-register keybinds for this operator to the 1, 2, 3 keys in Weight Paint mode:
|
|
||||||
1: Change to Add Brush.
|
|
||||||
2: Change to Subtract Brush.
|
|
||||||
3: Change to Blur Brush.
|
|
||||||
The brushes must have their default name, ie. "Add", "Subtract", "Blur".
|
|
||||||
|
|
||||||
### Entering Weight Paint Mode
|
### Entering Weight Paint Mode
|
||||||
The Toggle Weight Paint Mode operator lets you switch into weight paint mode easier.
|
The Toggle Weight Paint Mode operator lets you switch into weight paint mode easier.
|
||||||
Select your object and run the operator.
|
Simply select your mesh object and run the operator. The armature will be un-hidden and put into pose mode if necessary.
|
||||||
- It will find the first armature modifier of your mesh, if there is one. It will ensure the armature is visible and in pose mode.
|
Run the operator again to reset the armature object's visibility states to what they were before you entered weight paint mode.
|
||||||
- It will set the shading settings to a pure white.
|
|
||||||
- If your object's display type was set to Wire, it will set it to Solid.
|
|
||||||
Run the operator again to restore everything to how it was before.
|
|
||||||
|
|
||||||
I recommend setting up a keybind for this, eg.:
|
I recommend setting up a keybind for this, eg.:
|
||||||
<img src="docs/toggle_wp_shortcut.png" width="400" />
|
<img src="docs/toggle_wp_shortcut.png" width="400" />
|
||||||
@ -54,10 +44,13 @@ The Vertex Groups context menu is re-organized with more icons and better labels
|
|||||||
- **Delete Unselected Deform Groups**: Delete all deforming groups that don't correspond to a selected pose bone. Only in Weight Paint mode.
|
- **Delete Unselected Deform Groups**: Delete all deforming groups that don't correspond to a selected pose bone. Only in Weight Paint mode.
|
||||||
- **Ensure Mirror Groups**: If your object has a Mirror modifier, this will create any missing vertex groups.
|
- **Ensure Mirror Groups**: If your object has a Mirror modifier, this will create any missing vertex groups.
|
||||||
- **Focus Deforming Bones**: Reveal and select all bones deforming this mesh. Only in Weight Paint mode.
|
- **Focus Deforming Bones**: Reveal and select all bones deforming this mesh. Only in Weight Paint mode.
|
||||||
- **Focus Rogue Weights**: This real clever operator will cycle through vertex groups whose weights consist of more than a single island, then enter vertex masking mode and select the vertices of the smallest island. This still requires human eyes to check and make sure the islands are definitely not needed. You are meant to run this operator many times over and over to cycle through such vertex groups.
|
|
||||||
TODO: Operator to ensure symmetrical weights.
|
|
||||||
If you have any more suggestions, feel free to open an Issue with a feature request.
|
If you have any more suggestions, feel free to open an Issue with a feature request.
|
||||||
|
|
||||||
### Force Apply Mirror Modifier
|
### Force Apply Mirror Modifier
|
||||||
In Blender, you cannot apply a mirror modifier to meshes that have shape keys.
|
In Blender, you cannot apply a mirror modifier to meshes that have shape keys.
|
||||||
This operator tries to anyways, by duplicating your mesh, flipping it on the X axis and merging into the original. It will also flip vertex groups, shape keys, shape key masks, and even (attempt) shape key drivers, assuming everything is named with .L/.R suffixes.
|
This operator tries to anyways, by duplicating your mesh, flipping it on the X axis and merging into the original. It will also flip vertex groups, shape keys, shape key masks, and even (attempt) shape key drivers, assuming everything is named with .L/.R suffixes.
|
||||||
|
|
||||||
|
### Previous Features
|
||||||
|
Over time as more things have been fixed on Blender's side, some features have been removed. To avoid confusion, these are listed here:
|
||||||
|
- As of [Blender 3.1](https://developer.blender.org/rBa215d7e230d3286abbed0108a46359ce57104bc1), holding the Ctrl and Shift buttons in weight painting will use the Subtract and Blur brushes respectively, removing the need for the shortcuts on the 1, 2, 3 keys this addon used to add to provide quick brush switching.
|
||||||
|
- As of [Blender 3.0](https://developer.blender.org/rBSc0f600cad1d2d107d189b15b12e2fcc6bba0985c), the weight paint overlay is no longer multiplied on top of the underlying colors, removing the need for this addon to change shading or object display settings when using the Toggle Weight Paint mode operator.
|
@ -28,7 +28,6 @@ import importlib
|
|||||||
from . import smart_weight_transfer
|
from . import smart_weight_transfer
|
||||||
from . import force_apply_mirror
|
from . import force_apply_mirror
|
||||||
from . import toggle_weight_paint
|
from . import toggle_weight_paint
|
||||||
from . import change_brush
|
|
||||||
from . import weight_paint_context_menu
|
from . import weight_paint_context_menu
|
||||||
from . import vertex_group_operators
|
from . import vertex_group_operators
|
||||||
from . import vertex_group_menu
|
from . import vertex_group_menu
|
||||||
@ -39,7 +38,6 @@ modules = [
|
|||||||
smart_weight_transfer,
|
smart_weight_transfer,
|
||||||
force_apply_mirror,
|
force_apply_mirror,
|
||||||
toggle_weight_paint,
|
toggle_weight_paint,
|
||||||
change_brush,
|
|
||||||
weight_paint_context_menu,
|
weight_paint_context_menu,
|
||||||
vertex_group_operators,
|
vertex_group_operators,
|
||||||
vertex_group_menu,
|
vertex_group_menu,
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
import bpy
|
|
||||||
from bpy.props import *
|
|
||||||
from bpy.app.handlers import persistent
|
|
||||||
|
|
||||||
class EASYWEIGHT_OT_change_brush(bpy.types.Operator):
|
|
||||||
"""Change the weight paint brush to a specific brush"""
|
|
||||||
bl_idname = "brush.set_specific"
|
|
||||||
bl_label = "Set WP Brush"
|
|
||||||
bl_options = {'REGISTER', 'UNDO'}
|
|
||||||
|
|
||||||
brush: EnumProperty(name="Brush",
|
|
||||||
items=[('Add', 'Add', 'Add'),
|
|
||||||
('Subtract', 'Subtract', 'Subtract'),
|
|
||||||
('Draw', 'Draw', 'Draw'),
|
|
||||||
('Average', 'Average', 'Average'),
|
|
||||||
('Blur', 'Blur', 'Blur'),
|
|
||||||
],
|
|
||||||
default="Add")
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
brush_name = self.brush
|
|
||||||
brush = bpy.data.brushes.get(brush_name)
|
|
||||||
if not brush:
|
|
||||||
# Create the brush.
|
|
||||||
brush = bpy.data.brushes.new(brush_name, mode='WEIGHT_PAINT')
|
|
||||||
if brush_name == 'Add':
|
|
||||||
brush.blend = 'ADD'
|
|
||||||
if brush_name == 'Subtract':
|
|
||||||
brush.blend = 'SUB'
|
|
||||||
if brush_name == 'Blur':
|
|
||||||
brush.weight_tool = 'BLUR'
|
|
||||||
if brush_name == 'Average':
|
|
||||||
brush.weight_tool = 'AVERAGE'
|
|
||||||
|
|
||||||
# Configure brush.
|
|
||||||
value = 0.5 if brush.falloff_shape == 'SPHERE' else 1.0 # We use a darker color to indicate when falloff shape is set to Sphere.
|
|
||||||
if brush_name=='Add':
|
|
||||||
brush.cursor_color_add = [value, 0.0, 0.0, 1.0]
|
|
||||||
if brush_name=='Subtract':
|
|
||||||
brush.cursor_color_add = [0.0, 0.0, value, 1.0]
|
|
||||||
if brush_name=='Blur':
|
|
||||||
brush.cursor_color_add = [value, value, value, 1.0]
|
|
||||||
|
|
||||||
# Set the brush as the active one.
|
|
||||||
bpy.context.tool_settings.weight_paint.brush = brush
|
|
||||||
|
|
||||||
return { 'FINISHED' }
|
|
||||||
|
|
||||||
@persistent
|
|
||||||
def register_brush_switch_hotkeys(dummy):
|
|
||||||
# Without this, the hotkeys' properties get reset whenever the addon is disabled, which results in having to set the Add, Subtract, Blur brushes on the hotkeys manually every time.
|
|
||||||
# However, with this, the hotkey cannot be changed, since this will forcibly re-create the original anyways.
|
|
||||||
|
|
||||||
active_keyconfig = bpy.context.window_manager.keyconfigs.active
|
|
||||||
if not active_keyconfig: return # Avoid error when running without UI.
|
|
||||||
wp_hotkeys = active_keyconfig.keymaps['Weight Paint'].keymap_items
|
|
||||||
|
|
||||||
add_hotkey = wp_hotkeys.new('brush.set_specific',value='PRESS',type='ONE',ctrl=False,alt=False,shift=False,oskey=False)
|
|
||||||
add_hotkey.properties.brush = 'Add'
|
|
||||||
add_hotkey.type = add_hotkey.type
|
|
||||||
|
|
||||||
sub_hotkey = wp_hotkeys.new('brush.set_specific',value='PRESS',type='TWO',ctrl=False,alt=False,shift=False,oskey=False)
|
|
||||||
sub_hotkey.properties.brush = 'Subtract'
|
|
||||||
sub_hotkey.type = sub_hotkey.type
|
|
||||||
|
|
||||||
blur_hotkey = wp_hotkeys.new('brush.set_specific',value='PRESS',type='THREE',ctrl=False,alt=False,shift=False,oskey=False)
|
|
||||||
blur_hotkey.properties.brush = 'Blur'
|
|
||||||
blur_hotkey.type = blur_hotkey.type
|
|
||||||
|
|
||||||
def register():
|
|
||||||
from bpy.utils import register_class
|
|
||||||
register_class(EASYWEIGHT_OT_change_brush)
|
|
||||||
register_brush_switch_hotkeys(None)
|
|
||||||
bpy.app.handlers.load_post.append(register_brush_switch_hotkeys)
|
|
||||||
|
|
||||||
def unregister():
|
|
||||||
from bpy.utils import unregister_class
|
|
||||||
unregister_class(EASYWEIGHT_OT_change_brush)
|
|
||||||
bpy.app.handlers.load_post.remove(register_brush_switch_hotkeys)
|
|
@ -5,13 +5,12 @@ from bpy.types import Object, Operator, VIEW3D_MT_paint_weight, VIEW3D_MT_object
|
|||||||
|
|
||||||
# It does the following:
|
# It does the following:
|
||||||
# Set active object to weight paint mode
|
# Set active object to weight paint mode
|
||||||
# Make sure active object is not in wireframe or bounding box display type
|
|
||||||
# Find first armature via the object's modifiers.
|
# Find first armature via the object's modifiers.
|
||||||
# Ensure it is visible, select it and set it to pose mode.
|
# Ensure it is visible, select it and set it to pose mode.
|
||||||
|
|
||||||
# This allows you to start weight painting with a single button press from any state.
|
# This allows you to start weight painting with a single button press from any state.
|
||||||
|
|
||||||
# When running the operator again, it should restore everything to how it was before.
|
# When running the operator again, it should restore all armature visibility related settings to how it was before.
|
||||||
|
|
||||||
def get_armature_of_meshob(obj: Object):
|
def get_armature_of_meshob(obj: Object):
|
||||||
"""Find and return the armature that deforms this mesh object."""
|
"""Find and return the armature that deforms this mesh object."""
|
||||||
@ -26,12 +25,6 @@ def enter_wp(context) -> bool:
|
|||||||
obj = context.object
|
obj = context.object
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
|
|
||||||
# Store old display_type setting in a Custom Property on the Object.
|
|
||||||
obj['wpt_display_type'] = obj.display_type
|
|
||||||
# Ensure display_type is SOLID; weights don't display in WIRE or BOUNDS.
|
|
||||||
if obj.display_type not in ['SOLID', 'TEXTURED']:
|
|
||||||
obj.display_type = 'SOLID'
|
|
||||||
|
|
||||||
# Store old shading settings in a Custom Property dictionary in the Scene.
|
# Store old shading settings in a Custom Property dictionary in the Scene.
|
||||||
if 'wpt' not in wm:
|
if 'wpt' not in wm:
|
||||||
wm['wpt'] = {}
|
wm['wpt'] = {}
|
||||||
@ -40,7 +33,7 @@ def enter_wp(context) -> bool:
|
|||||||
wpt_as_dict = wpt.to_dict()
|
wpt_as_dict = wpt.to_dict()
|
||||||
|
|
||||||
# If we are entering WP mode for the first time or if the last time
|
# If we are entering WP mode for the first time or if the last time
|
||||||
# the operator was exiting WP mode, then save current shading info.
|
# the operator was exiting WP mode, then save current state.
|
||||||
if 'last_switch_in' not in wpt_as_dict or wpt_as_dict['last_switch_in']==False:
|
if 'last_switch_in' not in wpt_as_dict or wpt_as_dict['last_switch_in']==False:
|
||||||
wpt['active_object'] = obj
|
wpt['active_object'] = obj
|
||||||
|
|
||||||
@ -87,11 +80,6 @@ def leave_wp(context):
|
|||||||
obj = context.object
|
obj = context.object
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
|
|
||||||
# Restore object display type
|
|
||||||
if 'wpt_display_type' in obj:
|
|
||||||
obj.display_type = obj['wpt_display_type']
|
|
||||||
del obj['wpt_display_type']
|
|
||||||
|
|
||||||
if 'wpt' not in wm or 'mode' not in wm['wpt'].to_dict():
|
if 'wpt' not in wm or 'mode' not in wm['wpt'].to_dict():
|
||||||
# There is no saved data to restore from, nothing else to do.
|
# There is no saved data to restore from, nothing else to do.
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
Loading…
Reference in New Issue
Block a user