Saturday, February 11, 2023

doodle set bendybone segments and auto bind mesh in blender

i found when trying to create blendshapes in blender it was helpful to use bendybones to sculpt the shapes and i was constantly setting bendybone segments and rebinding mesh.  so these are a couple simple methods to set bendybone segments and auto bind mesh i created for blender 2.79. (i think some modifications would be needed to use in higher blender versions. please modify/use at your own risk)

import bpy

#make all bones in armature bendy bone with 12 segments
def setBendyBoneSegments(segments=12):
    """make all bones in armature bendy bone with given segments (tested in Blender 2.79)
    @param : segments - int number of segments for bendybone (default 12)
    @return : bool - True on success False otherwise
    """
    segments = int(segments)
    
    assert segments > 0
    
    #assert armature context
    if bpy.context.object.type != 'ARMATURE':
        print("Requires Armature selected")
        return False
        
    #assert in object mode
    currentMode = bpy.context.object.mode
    if currentMode != 'OBJECT':
        bpy.ops.object.mode_set(mode='OBJECT')
    
    armature = bpy.context.object
    
    #if armature not bbone draw type make it so
    if armature.data.draw_type != 'BBONE':
        armature.data.draw_type = 'BBONE'
        
    #set segments
    for bone in armature.data.bones:
        bone.bbone_segments = segments

    #restore selection
    bpy.ops.object.mode_set(mode=currentMode)

    return True



#auto bind mesh to armature
def autoBind():
    """
    auto bind mesh to armature - it removes any weights that might exist already (tested in Blender 2.79)
    """
    
    #should support pose and object mode
    currentMode = bpy.context.object.mode 
    assert currentMode == 'POSE' or currentMode == 'OBJECT'
    
    #assert have two thing selected
    assert len(bpy.context.selected_objects) == 2
    
    #assert first thing selected is mesh and second thing selected is armature
    armature = bpy.context.active_object
    mesh = [sel for sel in bpy.context.selected_objects if sel != armature][0]
    assert armature.type == 'ARMATURE'
    assert mesh.type == 'MESH'
    
    #remove all vertex groups from mesh if any
    _removeAllVertexGroups(mesh)   
    
    #auto bind mesh to armature
    try:
        bpy.ops.object.parent_set(type='ARMATURE_AUTO')
    except:
        print("could not autobind. please check you first selected mesh then armature. in object mode.")
        return False

    #restore mode
    bpy.ops.object.mode_set(mode=currentMode)
    

def _removeAllVertexGroups(mesh):
    """remove all vertex groups in mesh (tested in Blender 2.79)
    @param mesh - data object for mesh
    """
    #no vertex groups already so do nothing
    if len(mesh.vertex_groups) == 0:
        return True
        
    #save selection
    active = bpy.context.active_object
    selection = bpy.context.selected_objects
    
    #set seletion to mesh - required for operating on its vertex groups
    bpy.ops.object.mode_set(mode = 'OBJECT')
    bpy.ops.object.select_all(action = 'DESELECT')
    mesh.select = True
    bpy.context.scene.objects.active = mesh
    
    #remove all vertex groups on mesh
    bpy.ops.object.vertex_group_remove(all=True)     
    
    #restore selection
    bpy.ops.object.select_all(action = 'DESELECT')
    for obj in selection:
        obj.select = True
    bpy.context.scene.objects.active = active
    
    return True


"""
import imp
testTool = imp.load_source("tool","put path to python file here") #change to path to python file

#testTool.autoBind()

#testTool.setBendyBoneSegments(segments=10)
"""