Create bones function

Hi all,
I’m looking for a better way not to have to enumerate all the options that I need to use to create a bone.
The following is working, but it is redundant, and if I need to use an option I need to implement it:

import bpy

def createBone(name,options):
    ###need to be in edit mode
    bpy.ops.object.mode_set(mode='EDIT')
    bone = arma.edit_bones.new(bname)
    if 'head' in options:
        bone.head = options['head']
    if 'tail' in options:
        bone.tail = options['tail']
        
arma = bpy.data.armatures['Armature']
createBone('test',{'head':[0,0,0],'tail':[0,0,1]})

I would prefer something like that:

import bpy

def createBone(name,options):
    ###need to be in edit mode
    bpy.ops.object.mode_set(mode='EDIT')
    bone = arma.edit_bones.new(bname)
    for each in options:
        bone.each = options[each]

arma = bpy.data.armatures['Armature']
createBone('test',{'head':[0,0,0],'tail':[0,0,1]})

Is there a way to do it?
Thank you.
Mathias.

You can set an object’s attribute by string using setattr :wink:

for attribute in options.keys():
	setattr(bone, attribute, options[attribute])

This is probably not exactly what you are looking for, but I am betting you will get a good idea from it after looking at how I am using a list to do what I am doing. First, I am using two functions, kind of in the style as in your example, but then, I am using a list which seriously can shorten the whole process. I’ll list the two functions first, then look what comes after that.

# Make bone creation easy
def createBone(name="boneName", VHead=(0, 0, 0), VTail=(.1, 0, .1), roll=0, con=False):
    bpy.ops.object.mode_set(mode='EDIT')
    bData = bpy.context.active_object.data
    bone = bData.edit_bones.new(name)
    bone.head[:] = VHead
    bone.tail[:] = VTail
    bone.roll = roll
    bone.use_connect = con
    return bone

def boneExtrude(vector, name):
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.armature.extrude_forked(TRANSFORM_OT_translate={"value":vector})
    bpy.context.active_bone.name = name
    bone = bpy.context.active_bone
    return bone

Now I am using a list to create a whole series of bones:

        self.armature = new_armature('armature' +  self.str_n, x,y,z)
        start = [0, 0, 0] # Start at armature location
        J1 = [0, .12, 0] # Relative to armature location  # [.3, .1, .5],[.3, .22, .5]
        arm = [start, J1,[0, .14, 0],[0, .08, 0],[0, .1, 0],
              [0, .1, 0],[0, .098, 0],[0, .05, 0],[0, .044, 0],[0, .02, 0],      # MiddleJ1-4
              [.03, .098, -.006],[.011, .032, 0],[.01, .024, 0],[.008, .02, 0],  # IndexJ1-4
              [-.02, .098, -.006],[-.01, .042, 0],[-.007, .032, 0],[-.004, .02, 0],  # RingJ1-4 
              [-.046, .095, -.006],[-.016, .024, 0],[-.012, .02, 0],[-.01, .02, 0],  # PinkyJ1-4 
              [.008, .002, 0],[.044, .038, -0.01],[.02, .032, -0.006],[.01, .02, 0]] # ThumbJ1-4
        #
        if(self.leftright == 'right'):
            for coord in arm:
                coord[1] = coord[1] * -1
        self.J1 = createBone(arm[0], arm[1], self.name + 'J1')
        self.J2 = boneExtrude(arm[2], name + "J2")
        self.J3 = boneExtrude(arm[3], name + "J3")
        self.J4 = boneExtrude(arm[4], name + "J4")
        self.J5 = boneExtrude(arm[5], name + "J5")
        self.J6 = boneExtrude(arm[6], name + "J6")
        self.J7 = boneExtrude(arm[7], name + "J7")
        self.J8 = boneExtrude(arm[8], name + "J8")
        self.J9 = boneExtrude(arm[9], name + "J9")

As I said, this may not be exactly what you are looking for, but it may give you an idea on how to proceed. Incidently, you will notice that the last part came from a class . . . Note also, that if you use a list, you can use a list position more than once. For example, if you have 4 bones that will all be the same size, have all the same options, you could do something like:

location = [0,0,.4]    making bones on the z-axis, all the same length
arm[location]
# note that all the bone creations are using the same options from the list[0] position:
self.J2 = boneExtrude(arm[0], name + "J2")
self.J3 = boneExtrude(arm[0], name + "J3")
self.J4 = boneExtrude(arm[0], name + "J4")
self.J5 = boneExtrude(arm[0], name + "J5")

In my method though, createBone uses a coordinate system that requires an absolue start and end position for the fist bone, while the extrude only needs the endpoint, because the positioning is relative. Anyway, don’t know it this is of any help whatsoever, but it might spur on an idea or two.

Hi @Shawn_Irwin , thank you for your reply. your way is a very interesting way to create an armature, thank you for sharing! :+1:

@Travisty , thank you, that’s exactly what I was looking for. works perfectly!

import bpy

def createBone(name,options):
    ###need to be in edit mode
    bpy.ops.object.mode_set(mode='EDIT')
    bone = arma.edit_bones.new(bname)
    for attribute in options.keys():
        setattr(bone, attribute, options[attribute])
        
arma = bpy.data.armatures['Armature']
createBone('test',{'head':[0,0,0],'tail':[0,0,1]})

I didn’t know about this function of python, setAttr, it’s going to be very useful!!! :slight_smile:

1 Like