# What are my options for automatically filling in a missing vertex weight group?

I have imported a pre-existing, fully-rigged model into Blender 2.79b. Unfortunately, the source model contains some bones that Blender doesn't appear to know how to import correctly, and thus drops them entirely. (I can recreate the bones correctly afterward, that part's not a big deal.) As a result, about 10%-15% of the mesh contains vertices with missing vertex weights. (I can't control the original model, I'm stuck with how it is.)

However, I know that all vertices must have exactly 1 or 2 vertex groups, and their weights are correctly set to sum to 1.0. I also know that the missing groups do not overlap. Therefore, I could go through every vertex near the bone in question and check its groups:

• If the vertex has no groups, it must have a weight of 1.0 in a missing group.
• If the vertex has 1 group that's less than 1.0, it must belong in a missing group with a corresponding weight (e.g. if it's already in "shoulder_R" with weight 0.35, then it must also be in "arm_R" with weight 0.65).

I could do this manually, but that's a lot of work with lots of potential for messing up.

Is there a way to automatically assign a bunch of vertices to a vertex group that "fills in" their total weights to 1.0?

I tried a few things with weight painting but I didn't find anything that seemed to be what I was looking for. I'm not averse to scripting but have no experience with it.

I managed to put together an add-on script that does what I want. It takes some tabbing between object/edit mode to "bake in" what vertices you want it to operate on (didn't look too deeply into it), and you can only access it through the spacebar menu, but that's fine by me.

bl_info = {
"name":"Fill In Missing Weights",
"category":"Object",
}

import bpy
from decimal import *

class FillInWeights(bpy.types.Operator):
"""Fill In Missing Weights"""
bl_idname = "object.fill_in_weights"
bl_label = "Fill In Missing Weights"
bl_options = {"REGISTER","UNDO"}

missing_group_name = bpy.props.StringProperty(
name="Missing group name",
description="Name of the group to fill in.",
default="",
)
print_debug_info = bpy.props.BoolProperty(
name="Print debug info",
description="Output specific operations to console.",
default=False,
)

def execute(self,context):
obj = context.active_object
if not obj.vertex_groups:
self.report({"ERROR"},'Object has no vertex groups')
return {"CANCELLED"}
missing_group = obj.vertex_groups.get(self.missing_group_name)
if not missing_group: # group must exist already
self.report({"ERROR"},'Vertex group "'+self.missing_group_name+'" does not exist')
return {"CANCELLED"}
if self.print_debug_info:
print('Begin weight-fill operation on group "'+self.missing_group_name+'"')
bpy.ops.object.mode_set(mode="OBJECT")
for v in obj.data.vertices:
if not v.select: continue
if len(v.groups) == 0:
elif len(v.groups) == 1:
g = v.groups[0]
g_index,g_weight = g.group,Decimal(g.weight).quantize(Decimal("0.001")) # all known cases are 0.01, but just to be safe
if g_weight >= 1.0: continue
group = obj.vertex_groups[g_index]
target_weight = Decimal("1.00")-g_weight
print('Vertex in group '+group.name+' with weight '+str(g_weight)+': adding to group '+self.missing_group_name+' with weight '+str(target_weight))
# len(v.groups) >= 2: continue
bpy.ops.object.mode_set(mode="EDIT")
if self.print_debug_info:
print("Weight-fill complete.")
return {"FINISHED"}

def invoke(self,context,event):
return context.window_manager.invoke_props_dialog(self)

def register():
bpy.utils.register_class(FillInWeights)
def unregister():
bpy.utils.unregister_class(FillInWeights)

if __name__ == "__main__":
register()