[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [51217] trunk/blender: patch [#31919] limit the number of bone deform weights per vertex.

Campbell Barton ideasman42 at gmail.com
Tue Oct 9 12:56:36 CEST 2012


Revision: 51217
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=51217
Author:   campbellbarton
Date:     2012-10-09 10:56:35 +0000 (Tue, 09 Oct 2012)
Log Message:
-----------
patch [#31919] limit the number of bone deform weights per vertex. Many game engines require a limit of 4.
from Kesten Broughton (kestion)


Usage: In weight paint mode, select the mesh to have its weights culled. Click on "Limit Weights" button. A sub-panel will appear "Limit Number of Vertex Weights" with a slider field "Limit" which you can set to the appropriate level. The default level is 4, and it gets executed upon pressing "Limit Weights" so you will need to do an "undo" if your max bone limit is above 4. The checkbox "All Deform Weights" will consider all vertex weights, not just bone deform weights.

Modified Paths:
--------------
    trunk/blender/release/scripts/startup/bl_ui/space_view3d.py
    trunk/blender/release/scripts/startup/bl_ui/space_view3d_toolbar.py
    trunk/blender/source/blender/editors/object/object_intern.h
    trunk/blender/source/blender/editors/object/object_ops.c
    trunk/blender/source/blender/editors/object/object_vgroup.c

Modified: trunk/blender/release/scripts/startup/bl_ui/space_view3d.py
===================================================================
--- trunk/blender/release/scripts/startup/bl_ui/space_view3d.py	2012-10-09 10:53:20 UTC (rev 51216)
+++ trunk/blender/release/scripts/startup/bl_ui/space_view3d.py	2012-10-09 10:56:35 UTC (rev 51217)
@@ -1247,6 +1247,7 @@
         layout.operator("object.vertex_group_clean", text="Clean")
         layout.operator("object.vertex_group_levels", text="Levels")
         layout.operator("object.vertex_group_blend", text="Blend")
+        layout.operator("object.vertex_group_limit_total", text="Limit Total")
         layout.operator("object.vertex_group_fix", text="Fix Deforms")
 
         layout.separator()

Modified: trunk/blender/release/scripts/startup/bl_ui/space_view3d_toolbar.py
===================================================================
--- trunk/blender/release/scripts/startup/bl_ui/space_view3d_toolbar.py	2012-10-09 10:53:20 UTC (rev 51216)
+++ trunk/blender/release/scripts/startup/bl_ui/space_view3d_toolbar.py	2012-10-09 10:56:35 UTC (rev 51217)
@@ -967,6 +967,7 @@
         col.operator("object.vertex_group_clean", text="Clean")
         col.operator("object.vertex_group_levels", text="Levels")
         col.operator("object.vertex_group_blend", text="Blend")
+        col.operator("object.vertex_group_limit_total", text="Limit Total")
         col.operator("object.vertex_group_fix", text="Fix Deforms")
 
 

Modified: trunk/blender/source/blender/editors/object/object_intern.h
===================================================================
--- trunk/blender/source/blender/editors/object/object_intern.h	2012-10-09 10:53:20 UTC (rev 51216)
+++ trunk/blender/source/blender/editors/object/object_intern.h	2012-10-09 10:56:35 UTC (rev 51217)
@@ -214,6 +214,7 @@
 void OBJECT_OT_vertex_group_invert(struct wmOperatorType *ot);
 void OBJECT_OT_vertex_group_blend(struct wmOperatorType *ot);
 void OBJECT_OT_vertex_group_clean(struct wmOperatorType *ot);
+void OBJECT_OT_vertex_group_limit_total(struct wmOperatorType *ot);
 void OBJECT_OT_vertex_group_mirror(struct wmOperatorType *ot);
 void OBJECT_OT_vertex_group_set_active(struct wmOperatorType *ot);
 void OBJECT_OT_vertex_group_sort(struct wmOperatorType *ot);

Modified: trunk/blender/source/blender/editors/object/object_ops.c
===================================================================
--- trunk/blender/source/blender/editors/object/object_ops.c	2012-10-09 10:53:20 UTC (rev 51216)
+++ trunk/blender/source/blender/editors/object/object_ops.c	2012-10-09 10:56:35 UTC (rev 51217)
@@ -188,6 +188,7 @@
 	WM_operatortype_append(OBJECT_OT_vertex_group_levels);
 	WM_operatortype_append(OBJECT_OT_vertex_group_blend);
 	WM_operatortype_append(OBJECT_OT_vertex_group_clean);
+	WM_operatortype_append(OBJECT_OT_vertex_group_limit_total);
 	WM_operatortype_append(OBJECT_OT_vertex_group_mirror);
 	WM_operatortype_append(OBJECT_OT_vertex_group_set_active);
 	WM_operatortype_append(OBJECT_OT_vertex_group_sort);

Modified: trunk/blender/source/blender/editors/object/object_vgroup.c
===================================================================
--- trunk/blender/source/blender/editors/object/object_vgroup.c	2012-10-09 10:53:20 UTC (rev 51216)
+++ trunk/blender/source/blender/editors/object/object_vgroup.c	2012-10-09 10:56:35 UTC (rev 51217)
@@ -83,6 +83,19 @@
 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg);
 static void vgroup_delete_all(Object *ob);
 
+static int vertex_group_use_vert_sel(Object *ob)
+{
+	if (ob->mode == OB_MODE_EDIT) {
+		return TRUE;
+	}
+	else if (ob->type == OB_MESH && ((Mesh *)ob->data)->editflag & ME_EDIT_VERT_SEL) {
+		return TRUE;
+	}
+	else {
+		return FALSE;
+	}
+}
+
 static Lattice *vgroup_edit_lattice(Object *ob)
 {
 	Lattice *lt = ob->data;
@@ -704,7 +717,7 @@
 	int i, dvert_tot = 0;
 	const int def_nr = ob->actdef - 1;
 
-	const int use_vert_sel = (ob->type == OB_MESH && ((Mesh *)ob->data)->editflag & ME_EDIT_VERT_SEL) != 0;
+	const int use_vert_sel = vertex_group_use_vert_sel(ob);
 
 	if (!BLI_findlink(&ob->defbase, def_nr)) {
 		return;
@@ -1109,7 +1122,7 @@
 	int i, dvert_tot = 0;
 	const int def_nr = ob->actdef - 1;
 
-	const int use_vert_sel = (ob->type == OB_MESH && ((Mesh *)ob->data)->editflag & ME_EDIT_VERT_SEL) != 0;
+	const int use_vert_sel = vertex_group_use_vert_sel(ob);
 
 	if (!BLI_findlink(&ob->defbase, def_nr)) {
 		return;
@@ -1143,7 +1156,7 @@
 	int i, dvert_tot = 0;
 	const int def_nr = ob->actdef - 1;
 
-	const int use_vert_sel = (ob->type == OB_MESH && ((Mesh *)ob->data)->editflag & ME_EDIT_VERT_SEL) != 0;
+	const int use_vert_sel = vertex_group_use_vert_sel(ob);
 
 	if (lock_active && !BLI_findlink(&ob->defbase, def_nr)) {
 		return;
@@ -1221,7 +1234,7 @@
 	MDeformVert *dv, **dvert_array = NULL;
 	int i, dvert_tot = 0;
 	const int def_nr = ob->actdef - 1;
-	const int use_vert_sel = (ob->type == OB_MESH && ((Mesh *)ob->data)->editflag & ME_EDIT_VERT_SEL) != 0;
+	const int use_vert_sel = vertex_group_use_vert_sel(ob);
 
 	if (!BLI_findlink(&ob->defbase, def_nr)) {
 		return;
@@ -1389,13 +1402,119 @@
 	}
 }
 
+static int inv_cmp_mdef_vert_weights(const void *a1, const void *a2)
+{
+	/* qsort sorts in ascending order.  We want descending order to save a memcopy
+	 * so this compare function is inverted from the standard greater than comparison qsort needs.
+	 * A normal compare function is called with two pointer arguments and should return an integer less than, equal to,
+	 * or greater than zero corresponding to whether its first argument is considered less than, equal to,
+	 * or greater than its second argument.  This does the opposite. */
+	const struct MDeformWeight *dw1 = a1, *dw2 = a2;
+
+	if      (dw1->weight < dw2->weight) return  1;
+	else if (dw1->weight > dw2->weight) return -1;
+	else if (&dw1 < &dw2)               return  1; /* compare addresses so we have a stable sort algorithm */
+	else                                return -1;
+}
+
+/* Used for limiting the number of influencing bones per vertex when exporting
+ * skinned meshes.  if all_deform_weights is True, limit all deform modifiers
+ * to max_weights regardless of type, otherwise, only limit the number of influencing bones per vertex*/
+static int vertex_group_limit_total(Object *ob,
+                                    const int max_weights,
+                                    const int all_deform_weights)
+{
+	MDeformVert *dv, **dvert_array = NULL;
+	int i, dvert_tot = 0;
+	const int use_vert_sel = vertex_group_use_vert_sel(ob);
+	int is_change = FALSE;
+
+	ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
+
+	if (dvert_array) {
+		int defbase_tot = BLI_countlist(&ob->defbase);
+		const char *vgroup_validmap = (all_deform_weights == FALSE) ?
+		            BKE_objdef_validmap_get(ob, defbase_tot) :
+		            NULL;
+		int num_to_drop = 0;
+
+		/* only the active group */
+		for (i = 0; i < dvert_tot; i++) {
+
+			/* in case its not selected */
+			if (!(dv = dvert_array[i])) {
+				continue;
+			}
+
+			if (all_deform_weights) {
+				/* keep only the largest weights, discarding the rest
+				 * qsort will put array in descending order because of  invCompare function */
+				num_to_drop = dv->totweight - max_weights;
+				if (num_to_drop > 0) {
+					qsort(dv->dw, dv->totweight, sizeof(MDeformWeight), inv_cmp_mdef_vert_weights);
+					dv->dw = MEM_reallocN(dv->dw, sizeof(MDeformWeight) * max_weights);
+					dv->totweight = max_weights;
+					is_change = TRUE;
+				}
+			}
+			else {
+				MDeformWeight *dw_temp;
+				int bone_count = 0, non_bone_count = 0;
+				int j;
+				/* only consider vgroups with bone modifiers attached (in vgroup_validmap) */
+
+				num_to_drop = dv->totweight - max_weights;
+
+				/* first check if we even need to test further */
+				if (num_to_drop > 0) {
+					/* re-pack dw array so that non-bone weights are first, bone-weighted verts at end
+					 * sort the tail, then copy only the truncated array back to dv->dw */
+					dw_temp = MEM_mallocN(sizeof(MDeformWeight) * (dv->totweight), __func__);
+					bone_count = 0; non_bone_count = 0;
+					for (j = 0; j < dv->totweight; j++) {
+						BLI_assert(dv->dw[j].def_nr < defbase_tot);
+						if (!vgroup_validmap[(dv->dw[j]).def_nr]) {
+							dw_temp[non_bone_count] = dv->dw[j];
+							non_bone_count += 1;
+						}
+						else {
+							dw_temp[dv->totweight - 1 - bone_count] = dv->dw[j];
+							bone_count += 1;
+						}
+					}
+					BLI_assert(bone_count + non_bone_count == dv->totweight);
+					num_to_drop = bone_count - max_weights;
+					if (num_to_drop > 0) {
+						qsort(&dw_temp[non_bone_count], bone_count, sizeof(MDeformWeight), inv_cmp_mdef_vert_weights);
+						dv->totweight -= num_to_drop;
+						/* Do we want to clean/normalize here? */
+						MEM_freeN(dv->dw);
+						dv->dw = MEM_reallocN(dw_temp, sizeof(MDeformWeight) * dv->totweight);
+						is_change = TRUE;
+					}
+					else {
+						MEM_freeN(dw_temp);
+					}
+				}
+			}
+		}
+		MEM_freeN(dvert_array);
+
+		if (vgroup_validmap) {
+			MEM_freeN((void *)vgroup_validmap);
+		}
+	}
+
+	return is_change;
+}
+
 static void vgroup_clean(Object *ob, const float epsilon, int keep_single)
 {
 	MDeformWeight *dw;
 	MDeformVert *dv, **dvert_array = NULL;
 	int i, dvert_tot = 0;
 	const int def_nr = ob->actdef - 1;
-	const int use_vert_sel = (ob->type == OB_MESH && ((Mesh *)ob->data)->editflag & ME_EDIT_VERT_SEL) != 0;
+	const int use_vert_sel = vertex_group_use_vert_sel(ob);
 
 	if (!BLI_findlink(&ob->defbase, def_nr)) {
 		return;
@@ -1431,7 +1550,7 @@
 {
 	MDeformVert **dvert_array = NULL;
 	int i, dvert_tot = 0;
-	const int use_vert_sel = (ob->type == OB_MESH && ((Mesh *)ob->data)->editflag & ME_EDIT_VERT_SEL) != 0;
+	const int use_vert_sel = vertex_group_use_vert_sel(ob);
 
 	ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
 
@@ -2665,7 +2784,48 @@
 	                "Keep verts assigned to at least one group when cleaning");
 }
 
+static int vertex_group_limit_total_exec(bContext *C, wmOperator *op)
+{
+	Object *ob = ED_object_context(C);
 
+	const int limit = RNA_int_get(op->ptr, "limit");
+	const int all_deform_weights = RNA_boolean_get(op->ptr, "all_deform_weights");
+
+	if (vertex_group_limit_total(ob, limit, all_deform_weights)) {
+
+		DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+		WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list