analitics

Pages

Sunday, June 12, 2022

Blender 3D and python scripting - part 015.

The tutorial for today is about adding armature to the skin, and has a single line of source code:
bpy.ops.object.skin_armature_create(modifier="SK")
This will add an armature with bones for each edge based on the skin modifier.
See the result of this ...
The full source code is this:
import bpy
import random

# import bmesh 
import bmesh

MinNubmer = -10
MaxNumber = 10

# Clean up the area , uncoment the next two row to keep
# branch after running the script
#bpy.ops.object.select_all(action="SELECT")
#bpy.ops.object.delete()

# Number of branches
branch = 4
# Create the verts array
verts = [(0,0,0)]
# Create the edges array
edges = [(0,0)]
# Create the faces array
faces = []

# define random number for X and Y axis 
def RN():
    return  random.randint(MinNubmer, MaxNumber) / 20 

# define random number for positive Z axis
def RNZ():
    return  random.randint(10, 50) / 10  

# create a list of branch thicknesses
rand_list = []

name_branch = "TreeMesh"
# define createBranch 

def createBranch(branch, name_branch):
    # Create the mesh for branch 
    mesh = bpy.data.meshes.new(name_branch) 
    for i in range(1,branch):
        rand_list.append(RNZ()/30)
        # sort all reverse by thicknesses
        rand_list.sort(reverse=True)

    # generate vertices list for drawing the branch
    for i in range(1,branch):
        verts.append((rand_list[i-1] +0.1,rand_list[i-1]+0.1,RNZ()))
        edges.append((i-1,i))

    # sort the list of vertices by last number witch is Z axis 
    verts.sort(key=lambda x: x[2])
    # create branch update and validate, see documentation
    mesh.from_pydata(verts, edges, faces) 
    mesh.update()
    mesh.validate()
    # Create object to hold the mesh branch with the new name for object
    obj = bpy.data.objects.new(name_branch+'_Obj', mesh)
    return obj

# create a new branch     
def createNewBranch(obj_branch, n):
    bpy.ops.object.mode_set(mode="EDIT", toggle=False)
    me = obj_branch.data
    bm = bmesh.from_edit_mesh(me)
    bm.select_mode = {'VERT'}

    for i,v in enumerate(bm.verts):
        # select only by the index of list 
        if i == n:
            v.select = ( v.co.x > 0.0 )
            v2 = v    
        else: 
            v.select = False
    # flush and update view 
    v1 = bm.verts.new( (RN()+(v.co.x) + 1.0 , RN()+(v.co.y) + 1.0 , (v.co.z) - (v.co.z)/3) )
    #v1 = bm.verts.new(1, 1, 3)
    bm.edges.new((v1, v2))
    rand_list.append(0.01)
    rand_list.sort(reverse=True)
    # update 
    bm.select_flush_mode()   
    me.update()
    #mesh.validate()
    #bmesh.update_edit_mesh(obj_branch.data)

# use the createBranch
obj_branch = createBranch(branch, name_branch)


# now set up shape key in Blender
mesh=obj_branch.data
sk_basis = obj_branch.shape_key_add(name='Basis',from_mix=False)
sk_basis.interpolation = 'KEY_LINEAR'
# must set relative to false here
obj_branch.data.shape_keys.use_relative = False

# create new shape key
sk = obj_branch.shape_key_add(name='Deform',from_mix=False)
sk.interpolation = 'KEY_LINEAR'
sk.slider_min = 0
sk.slider_max = 2

# ... and add it to the scene
scene = bpy.context.scene
scene.collection.objects.link(obj_branch)

# this will fix the error ...  mode_set_poll()
bpy.context.view_layer.objects.active = obj_branch  

createNewBranch(obj_branch, 1)

# print tool for developing area 
def print_python_console(data):
    for window in bpy.context.window_manager.windows:
        screen = window.screen
        for area in screen.areas:
            if area.type == 'CONSOLE':
                override = {'window': window, 'screen': screen, 'area': area}
                bpy.ops.console.scrollback_append(override, text=str(data), type="OUTPUT")

# used to see the size of radius skin for each vertices
print_python_console(rand_list)

# fix error :  skin modifier is locked when using edit mode.
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)
# add the skin modifier
obj_branch.modifiers.new(name="SK", type="SKIN")
bpy.context.view_layer.objects.active = obj_branch  
# get the skin vertices layers
skin_vertices = obj_branch.data.skin_vertices
# get the layer
skin_layer = skin_vertices[0]
for i in range(1,branch+1):
    # assigns radius for each vertice to sized the branch 
    skin_layer.data[i-1].radius = (rand_list[i-1], rand_list[i-1]) 
    #Indices 0 and 1 are the vertex indices
    skin_layer.data[i].radius = (rand_list[i-1],rand_list[i-1])

bpy.ops.object.skin_armature_create(modifier="SK")

# set modes for user 
bpy.ops.object.mode_set(mode="EDIT", toggle=False)
bpy.ops.object.skin_root_mark()
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)