Saturday, 28 May 2011

Today's Top Tip: Workaround for buggy auto-weighting in Blender

If you're using auto-weighting in blender and you come across a complex mesh where it just isn't working - you probably have flipped normals.  Just tab into edit mode and W>flip.  If that doesn't work  my workaround was to build a much lower resolution mesh with nice clean topology for auto-weighting, then use this script which I quickly cobbled together to proximity copy weights.  It will copy all the weights from the source object to the target object, but be warned it will overwrite any existing vertex groups on the target, which you might be using for other non-binding related tasks.







import bpy


from_object=bpy.data.objects['coat_sim']
to_object=bpy.data.objects['coat_wind']
vert_sample=3






def copy_weights(from_object,to_object,copy_from_vert_index_list,copy_to_vert_index):
    #copy_from_vert_list is a list of tuples (vert index, weight)
    
    #dict organised by groupindex:weight
    from_weights=dict()
    
    #iterate over the from vertices
    for (each_copy_vertex_index,each_copy_vertex_weight) in copy_from_vert_index_list:
        for each_group in from_object.data.vertices[each_copy_vertex_index].groups:
            if each_group.group not in from_weights:
                from_weights[each_group.group]=(each_group.weight*each_copy_vertex_weight)
            else:
                from_weights[each_group.group]+=(each_group.weight*each_copy_vertex_weight)
                
    print(from_weights)
    
    #iterate over the groups in the to vertex
    for each_group in to_object.data.vertices[copy_to_vert_index].groups:
        if each_group.group in from_weights:
            each_group.weight=from_weights[each_group.group]
        else:
            each_group.weight=0
        




print('--')


#select the to object
bpy.ops.object.select_all(action='DESELECT')
bpy.context.scene.objects.active=to_object
to_object.select=True
#delete all vgs
bpy.ops.object.vertex_group_remove(all=True)


#to:from
index_lookup=dict()


#name=[from,to]
index_pairs=dict()


for index,each_group in enumerate(from_object.vertex_groups):
    index_pairs[each_group.name]=[index,-1]
    to_object.vertex_groups.new(each_group.name)
    
for index,each_group in enumerate(to_object.vertex_groups):
    if each_group.name in index_pairs.keys():
        index_pairs[each_group.name][1]=index


for each_pair in index_pairs.values():
    if each_pair[1]==-1:
        print(from_object.vertex_groups[each_pair[0]].name+' is missing')
    else:
        index_lookup[each_pair[1]]=each_pair[0]


#add all the vertices in the to object to each group




for active_group_index in range(0,len(to_object.vertex_groups)):
    to_object.vertex_groups.active_index=active_group_index
    #enter edit mode
    bpy.ops.object.editmode_toggle()
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.object.vertex_group_assign(new=False)
    bpy.ops.object.editmode_toggle()




#for each point in the from object


for to_vertex_index,to_vertex in enumerate(to_object.data.vertices):
    to_vert_pos=to_vertex.co*to_object.matrix_world
    
    distance_lookup=dict()
    
    for from_vertex_index,from_vertex in enumerate(from_object.data.vertices):
        from_vert_pos=from_vertex.co*from_object.matrix_world
        
        dist=(to_vert_pos-from_vert_pos).length
        
        distance_lookup[dist]=from_vertex_index
    
    if 0 in distance_lookup:
        chosen_from_vert=distance_lookup[0]
        #copy the weights from this vertex
        copy_weights(from_object,to_object,[(chosen_from_vert,1)],to_vertex_index)
    
    else:
        #order by min dist
        sorted_distances=sorted(distance_lookup.keys())  
        
        samples=[]
        sum_weighting=0
        for temp in range(0,vert_sample):
            this_weighting=1/sorted_distances[temp]
            samples.append([distance_lookup[sorted_distances[temp]],this_weighting])
            sum_weighting+=this_weighting
        
        for temp in range(0,vert_sample):
            samples[temp][1]/=sum_weighting
        
            
        copy_weights(from_object,to_object,samples,to_vertex_index)
            
        

No comments:

Post a Comment