Tuesday, July 18, 2023

some modeling scripting doodles for Blender 2.79

these are a couple of method doodles/sketches i wrote to help with some simple modeling related tasks in Blender 2.79 still a work in progress.  it has some examples of using ops, modifiers, vertex groups.  i haven't put these into an addon yet but hope some of the ideas are helpful.  (they're may be bugs so please modify use at your own risk - also some modifications will probably be needed to make them work in higher blender versions) 

 

import bpy

def toggleSmooth(levels=3):
    """toggle smooth on selected mesh.
    it creates subdivision surface modifier or removes all subdiv modifiers on mesh
    @param levels: number of levels to use in smoothing
    """
    if not bpy.context.selected_objects:
        print("requires a single mesh selected to duplicate")
        return False
    
    meshObj = bpy.context.object
    
    #if subdiv modifier(s) exist remove them
    #otherwise create a new one and increase smoothing
    isSmooth = False
    for modifier in meshObj.modifiers:
        if modifier.type == 'SUBSURF':
            isSmooth = True
            break

    if isSmooth:
        #remove smoothing
        for modifier in meshObj.modifiers:
            if modifier.type == 'SUBSURF':        
                meshObj.modifiers.remove(modifier)
    else:
        #add smoothing
        mod = meshObj.modifiers.new('Created_Smoothing',type='SUBSURF')
        mod.levels = levels
        #force refresh for blender 2.79 for display issue
        curFrame = bpy.context.scene.frame_current
        bpy.context.scene.frame_set(curFrame)
        
    return True

def makeCleanDuplicate(applyMod=True):
    """make a clean duplicate of mesh
    it applies all modifiers, deletes all vertex groups, deletes all shapekeys
    todo: possibly clear parent
    todo: possibly preserve shapekey pose in case source mesh has a shapkey on we want to preserve
    """
    if not bpy.context.selected_objects:
        print("requires a single mesh selected to duplicate")
        return False
        
    bpy.ops.object.duplicate()
    meshObj = bpy.context.object #should be duplicated mesh now selected
    
    #remove vertex groups
    bpy.ops.object.vertex_group_remove(all=True)
    
    #remove shapekeys
    bpy.ops.object.shape_key_remove(all=True)
    
    #apply all modifiers. todo: make an option to remove modifiers instead of apply
    for modifier in meshObj.modifiers:
        if applyMod:
            bpy.ops.object.modifier_apply(apply_as='DATA', modifier = modifier.name )

    return True
    
    

#todo make the duplicates into cleaner code - maybe a class - CleanShapekeyCopier
def duplicateSelectedLatticeShapekey():
    """make a clean duplicate mesh for selected lattice shapekey
    it applies all modifiers, deletes all vertex groups, deletes all shapekeys
    """
    
    selection = bpy.context.selected_objects or []
    if not len(bpy.context.selected_objects) == 2:
        print("requires a lattice and mesh selected")
        return False
    
    latticeObj = [sel for sel in selection if sel.type == 'LATTICE'][0]
    srcMeshObj = [sel for sel in selection if sel.type == 'MESH'][0]  
    #selObj = bpy.context.selected_objects[0]
    
    activeShapekeyIndex = latticeObj.active_shape_key_index
    
    ####
    #preserve shapekey pose
    #activate selected shapekey
    latticeObj.data.shape_keys.key_blocks[activeShapekeyIndex].value = 1.0
    ####

    bpy.ops.object.select_all(action = 'DESELECT')
    srcMeshObj.select = True #might need to make it active
    
    bpy.ops.object.duplicate()
    meshObj = bpy.context.object #should be duplicated mesh now selected
    
    
    #remove vertex groups
    #bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    if len(meshObj.vertex_groups) > 0: #will error if try to remove non existing vertex groups
        bpy.ops.object.vertex_group_remove(all=True)
    
    applyMod = True
    #apply all modifiers. todo: make an option to remove modifiers instead of apply
    for modifier in meshObj.modifiers:
        if applyMod:
            bpy.ops.object.modifier_apply(apply_as='DATA', modifier = modifier.name )

    #restore original lattice - needs to be after lattice modifier is applied to duplicated mesh
    latticeObj.data.shape_keys.key_blocks[activeShapekeyIndex].value = 0.0
    
    return True
    
    
def duplicateSelectedMeshShapekey():
    """make a clean duplicate mesh for selected shapekey (want to support lattices or mesh shapekeys)
    it applies all modifiers, deletes all vertex groups, deletes all shapekeys
    """
    
    
    if not bpy.context.selected_objects:
        print("requires a single mesh selected to duplicate")
        return False
        
    #selObj = bpy.context.selected_objects[0]
    
    bpy.ops.object.duplicate()
    meshObj = bpy.context.object #should be duplicated mesh now selected
    
    activeShapekeyIndex = meshObj.active_shape_key_index
    basisShapekeyIndex = 0 #might need to change this
    
    ####
    #preserve shapekey pose
    #activate selected shapekey
    meshObj.data.shape_keys.key_blocks[activeShapekeyIndex].value = 1.0
    #remove all shapekeys
    bpy.ops.object.shape_key_remove(all=True)
    ####
    
    
    #remove vertex groups
    #bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    if len(meshObj.vertex_groups) > 0: #will error if try to remove non existing vertex groups
        bpy.ops.object.vertex_group_remove(all=True)
    
    applyMod = True
    #apply all modifiers. todo: make an option to remove modifiers instead of apply
    for modifier in meshObj.modifiers:
        if applyMod:
            bpy.ops.object.modifier_apply(apply_as='DATA', modifier = modifier.name )

    return True
    

def addSuffixToSelected(suffix=".L"):
    """add suffix to all selected
    """
    selection = bpy.context.selected_objects
    for sel in selection:
        curName = sel.name
        if not curName.endswith(suffix):
            sel.name = curName+suffix
            
    
def splitBySelectedEdgeLoop():
    """split mesh by selected edgeloop
    """
    if bpy.context.object.mode != 'EDIT':
        print("need to have an edgeloop selected in edit mode. doing nothing")
        return False
        
    bpy.ops.mesh.edge_split()
    bpy.ops.mesh.separate(type='LOOSE')

    return True

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

testTool.addSuffixToSelected(suffix=".L") #requires ex: meshes selected to rename

testTool.duplicateSelectedMeshShapekey() #requires mesh selected
testTool.duplicateSelectedLatticeShapekey() #requires both mesh and lattice selected, order doesnt matter

testTool.toggleSmooth()
#testTool.makeCleanDuplicate()
#testTool.splitBySelectedEdgeLoop()
"""