6
$\begingroup$

I have a bezier curve that I created in Inkscape and I want to convert it to an armature, where each node of the curve is connected by a bone. See example below:

enter image description here

Is there a way to do this in Blender automatically?

$\endgroup$

2 Answers 2

8
$\begingroup$

Can also do this straight from the curves bezier points.

Test script, select the curve in object mode. Note for cyclic curves cannot create a circular parent structure for bones, eg the first bone can't have the last bone as a parent. AFAIK.

import bpy
context = bpy.context
scene = context.scene
curve_obj = context.object
curve = curve_obj.data

arm = bpy.data.armatures.new("BezArmature")
arm_obj = bpy.data.objects.new("BezArmature", arm)
scene.objects.link(arm_obj)

scene.objects.active = arm_obj
bpy.ops.object.mode_set(mode='EDIT')
mw = curve_obj.matrix_world
arm_obj.matrix_world = mw
for spline in curve.splines:
    points = [bp.co for bp in spline.bezier_points]
    if spline.use_cyclic_u:
        points.append(points[0])
    parent = None
    for i in range(len(points)-1):
        bone = arm.edit_bones.new("Bone")
        bone.head = points[i]
        bone.tail = points[i+1]
        bone.parent = parent
        bone.use_connect = True
        parent = bone
bpy.ops.object.mode_set(mode='OBJECT')

enter image description here

$\endgroup$
2
  • $\begingroup$ Just want to add note: script doesn't work in local viewport mode $\endgroup$ Commented Oct 11, 2017 at 15:42
  • $\begingroup$ @Lambdadelta yes.. barmy a bmesh for armatures would be handy, Local mode it creates the armature object, but no bones. Getting the view3d area to toggle local / global view is a bit out of the scope of the Q IMO.. Thanks for the heads up tho, good to know. $\endgroup$
    – batFINGER
    Commented Oct 12, 2017 at 19:15
4
$\begingroup$

I created a script which solves your problem, first it cycles through all edges and finds an edge loop, then it creates bones along the vertices' positions.

import bpy

def CreateBoneChainFromVertices(switch_direction = False):
    scn = bpy.context.scene
    if (None ==scn.objects.active):
        return
    obj = scn.objects.active
    if (obj.type != 'MESH'):
        return
    bpy.ops.object.mode_set(mode='OBJECT')

    edgesA = []
    edgesB = []
    for i in range(len(obj.data.edges)):
        ver = obj.data.edges[i].vertices
        edgesA.append(ver[0])
        edgesB.append(ver[1])

    chain = []
    chain.append(edgesA[0])
    while(True):
        current = chain[len(chain)-1]
        if current in edgesA:
            idx = edgesA.index(current)
            next = edgesB[idx]
            del edgesA[idx]
            del edgesB[idx]
            chain.append(next)
        elif current in edgesB:
            idx = edgesB.index(current)
            next = edgesA[idx]
            del edgesA[idx]
            del edgesB[idx] 
            chain.append(next)
        else:
            if (chain[0] in edgesA) or (chain[0] in edgesB):
                chain = list(reversed(chain))
            else:
                break
    if switch_direction:
        chain = list(reversed(chain))

    amt = bpy.data.armatures.new(obj.name + "_vBones")
    rig = bpy.data.objects.new(obj.name + '_vRig', amt)
    scn.objects.link(rig)
    scn.objects.active = rig
    scn.update()

    print(chain, "here we go")
    bpy.ops.object.editmode_toggle()
    for i in range(0, len(chain) - 1):
        bone = amt.edit_bones.new(str(i + 1))
        bone.head = obj.data.vertices[chain[i]].co
        bone.tail = obj.data.vertices[chain[i + 1]].co
    for i in range(0, len(amt.edit_bones) - 1):
        amt.edit_bones[i + 1].parent = amt.edit_bones[i]
        amt.edit_bones[i + 1].use_connect = True
    bpy.ops.object.editmode_toggle()

# optional parameter: (bool) switch direction
CreateBoneChainFromVertices(True)

The object has to be a mesh object. If it is not a mesh object, convert it. Alt+C > To Mesh

If you have more than one edge loop, split them into separate parts. P > By loose parts

Select the object, paste the script into the text editor and click on Run Script.

enter image description here

$\endgroup$
2
  • $\begingroup$ Thanks for the script! It works although I noticed that if I rescale the curve I have to apply the scale before running the script. $\endgroup$ Commented Dec 11, 2016 at 19:56
  • $\begingroup$ @Leander: Your answer cover this Question (see description) blender.stackexchange.com/questions/159600/…, don't you want to answer this with your script updated to 2.8? $\endgroup$
    – vklidu
    Commented Nov 30, 2019 at 11:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .