diff --git a/scripts/startup/bl_ui/properties_data_mesh.py b/scripts/startup/bl_ui/properties_data_mesh.py index 0ad7cfb0d5f..a6ad3198492 100644 --- a/scripts/startup/bl_ui/properties_data_mesh.py +++ b/scripts/startup/bl_ui/properties_data_mesh.py @@ -272,7 +272,11 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel): sub.operator("object.vertex_group_select", text="Select") sub.operator("object.vertex_group_deselect", text="Deselect") - layout.prop(context.tool_settings, "vertex_group_weight", text="Weight") + col = layout.column(align=True) + col.use_property_split = True + col.separator() + col.prop(context.tool_settings, "vertex_group_weight", text="Weight") + col.prop(context.tool_settings, "use_auto_normalize", text="Auto Normalize") draw_attribute_warnings(context, layout, None) diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc index 235a1b1ea61..69c2053af7e 100644 --- a/source/blender/editors/object/object_vgroup.cc +++ b/source/blender/editors/object/object_vgroup.cc @@ -1341,21 +1341,14 @@ static void vgroup_levels_subset(Object *ob, static bool vgroup_normalize_all(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, - const int subset_count, const bool lock_active, ReportList *reports) { MDeformVert *dv, **dvert_array = nullptr; int i, dvert_tot = 0; const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; - const bool use_vert_sel = vertex_group_use_vert_sel(ob); - if (subset_count == 0) { - BKE_report(reports, RPT_ERROR, "No vertex groups to operate on"); - return false; - } - vgroup_parray_alloc(static_cast(ob->data), &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { @@ -1411,6 +1404,35 @@ static bool vgroup_normalize_all(Object *ob, return false; } +/** + * If the currently active vertex group is for a deform bone, normalize all + * vertex groups that are for deform bones. + * + * \param lock_active: If true, the active vertex group will be left untouched, + * and the remaining deform groups will be normalized to occupy the remaining + * weight not used by it. + */ +static void vgroup_normalize_all_deform_if_active_is_deform(Object *ob, + const bool lock_active, + ReportList *reports) +{ + int r_defgroup_tot = BKE_object_defgroup_count(ob); + bool *defgroup_validmap = BKE_object_defgroup_validmap_get(ob, r_defgroup_tot); + const int def_nr = BKE_object_defgroup_active_index_get(ob) - 1; + + /* Only auto-normalize if the active group is bone-deforming. */ + if (defgroup_validmap[def_nr] == true) { + int subset_count, vgroup_tot; + const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( + ob, WT_VGROUP_BONE_DEFORM, &vgroup_tot, &subset_count); + + vgroup_normalize_all(ob, vgroup_validmap, vgroup_tot, lock_active, reports); + MEM_SAFE_FREE(vgroup_validmap); + } + + MEM_SAFE_FREE(defgroup_validmap); +} + enum { VGROUP_TOGGLE, VGROUP_LOCK, @@ -2714,13 +2736,18 @@ void OBJECT_OT_vertex_group_remove(wmOperatorType *ot) /** \name Vertex Group Assign Operator * \{ */ -static wmOperatorStatus vertex_group_assign_exec(bContext *C, wmOperator * /*op*/) +static wmOperatorStatus vertex_group_assign_exec(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = context_object(C); Scene &scene = *CTX_data_scene(C); vgroup_assign_verts(ob, scene, ts->vgroup_weight); + + if (ts->auto_normalize) { + vgroup_normalize_all_deform_if_active_is_deform(ob, true, op->reports); + } + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -2818,6 +2845,11 @@ static wmOperatorStatus vertex_group_remove_from_exec(bContext *C, wmOperator *o } } + ToolSettings *ts = CTX_data_tool_settings(C); + if (ts->auto_normalize) { + vgroup_normalize_all_deform_if_active_is_deform(ob, false, op->reports); + } + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); @@ -3096,8 +3128,14 @@ static wmOperatorStatus vertex_group_normalize_all_exec(bContext *C, wmOperator const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type( ob, subset_type, &vgroup_tot, &subset_count); - changed = vgroup_normalize_all( - ob, vgroup_validmap, vgroup_tot, subset_count, lock_active, op->reports); + if (subset_count == 0) { + BKE_report(op->reports, RPT_ERROR, "No vertex groups to operate on"); + changed = false; + } + else { + changed = vgroup_normalize_all(ob, vgroup_validmap, vgroup_tot, lock_active, op->reports); + } + MEM_freeN(vgroup_validmap); if (changed) { diff --git a/source/blender/makesrna/intern/rna_scene.cc b/source/blender/makesrna/intern/rna_scene.cc index fd9cc0e7770..c1b868be031 100644 --- a/source/blender/makesrna/intern/rna_scene.cc +++ b/source/blender/makesrna/intern/rna_scene.cc @@ -3272,7 +3272,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Weight Paint Auto-Normalize", "Ensure all bone-deforming vertex groups add up " - "to 1.0 while weight painting"); + "to 1.0 while weight painting or assigning to vertices"); RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data"); prop = RNA_def_property(srna, "use_lock_relative", PROP_BOOLEAN, PROP_NONE);