0
$\begingroup$

I used the local coordinates of the armature newbone.tail = arm.matrix_world.inverted() * o.location to create a bone between its parent and an empty as shown below:

import bpy

scene = bpy.context.scene
arm = bpy.data.objects['Armbvh']
newbonename = 'My_NewBoneMarker'

bpy.ops.object.mode_set(mode='EDIT')

newbone = arm.data.edit_bones.new(newbonename)
parentbone = arm        
o = scene.objects.get(newbonename)

newbone.tail = arm.matrix_world.inverted() * o.location
if newbone.name != 'Origin':
    newbone.use_connect =  True

newbone.parent = arm.data.edit_bones['ParentBone']
newbone.head = arm.data.edit_bones['ParentBone'].tail
bpy.ops.object.mode_set(mode='OBJECT')

The problem I'm facing is that the new bone is very big as shown below because the rest pose of the armature is at (0,0,0) so the newbone is created between the parentbone in edit mode and the empty which is a big distance as shown below. Any advice how to fix this? I want the bone to be created between the location of the bone in pose mode in frame 0 and the location of the empty as demonstrated below.

My .blend file can be found here:

This is the problem in edit mode (rest position):

enter image description here

Problem in Pose position:

enter image description here

This is what I where I want the new bone to be created to have a length between the parent bone in pose mode and the empty as shown below:

enter image description here

$\endgroup$
1
$\begingroup$

The principle is to take the delta between the previous bone (shoulder) tail and the empty's position (in local coordinate) in pose mode.

Then add this delta to the previous bone's tail in edit mode.

A point where I have spent a lot of time (as newbie here...): 'Vector' in Python is a pointer. So if you don't copy (v.copy()) the vector before you switch between pose and edit mode, the values are changed!

But from that, the result is finally simple:

import bpy

scene = bpy.context.scene
arm = bpy.data.objects['Armbvh']
newbonename = 'My_NewBoneMarker'

empty = scene.objects.get(newbonename)
emptyInLocal = arm.matrix_world.inverted() * empty.location

#Get the parent bone in POSE MODE
bpy.ops.object.mode_set(mode='POSE')

parentBonePose = arm.pose.bones['ParentBone']
parentBonePoseTail = parentBonePose.tail.copy() #Use copy() as if not switching to edit mode will change the values

#Go to edit mode
bpy.ops.object.mode_set(mode='EDIT')

parentBoneEdit = arm.data.edit_bones['ParentBone']

newbone = arm.data.edit_bones.new(newbonename)

if newbone.name != 'Origin':
    newbone.use_connect =  True

newbone.parent = parentBoneEdit
newbone.head = parentBoneEdit.tail
#The tail is the head + the delta between the empty and the tail in pose mode
newbone.tail = newbone.head + (emptyInLocal - parentBonePoseTail)

bpy.ops.object.mode_set(mode='OBJECT')
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.