12
$\begingroup$

I have a bone and I need to get the location of its head and tail. I know that I can search for the corresponding edit_bone, but this list is only filled in edit mode. Is there a way to get both locations from within pose mode?

$\endgroup$
1
  • $\begingroup$ That should not lead to the desired result. When switching to edit mode I only can get the edit bones which are in default pose but not at the actual pose I defined in pose mode. $\endgroup$ Commented Aug 29, 2014 at 21:56

3 Answers 3

11
$\begingroup$

This simple script will print to the console and move two Empties to the location of the active bone in pose mode (last selected).

import bpy
from bpy import context

armature = "Armature" # change this to the name of your armature 

tail = bpy.data.objects[armature].location + context.active_pose_bone.tail
head = bpy.data.objects[armature].location + context.active_pose_bone.head

print(tail, head)
bpy.data.objects['Empty.head'].location = head
bpy.data.objects['Empty.tail'].location = tail

You will need to have two empties in your scene and on a visible layer, named Empty.tail and Empty.head in order for lines 10 and 11 to work. If not comment out lines 10 and 11 with a #.

Lines 6 and 7 get the locations of the armature and the active bone's head and tail, then adds them together. bpy.data.objects[armature] accesses an object with the name specified in the variable armature. If your armature has a different name, change it in the variable defined on line 4.

Line 9 print(tail, head) just spits the two vectors to the console.

Lines 10 and 11 sets the location of the two named empties to the location of the head and tail of the bone. I found this way easier then copying numbers from the console.

Note that you need to be in pose mode for this to work. Also the armature can got be rotated or scaled in object mode.

$\endgroup$
3
$\begingroup$

The answer by @David does not look okay to me. I might be wrong.

  1. The context.active_pose_bone.tail gives us location with respect to the parent bone.
  2. The context.active_pose_bone.tail_local will give us the location in armature local space, which is easy to transfer to the global space. To get to the world space we need to multiply with the world matrix of the armature object.

I find this answer on blenderartist helpful. link

Pythonic implementaion Target - get the world coordinates of the bone with variable bone_name on the armature mesh_1

R = bpy.data.objects['mesh_1'].matrix_world.to_3x3()
R = np.array(R)

t = bpy.data.objects['mesh_1'].matrix_world.translation
t = np.array(t) 

print(f"R = {R.shape}\n{R}")
print(f"t = {t.shape}\n{t}")

local_location = bpy.data.objects['mesh_1'].data.bones[bone_name].head_local
local_location = np.array(local_location)
print(f"local position = {local_location.shape}\n{local_location}")

loc = np.dot(R, local_location) + t 
print(f"final loc = {loc.shape}\n{loc}")

return [loc[0], loc[1], loc[2]]
$\endgroup$
1
  • 1
    $\begingroup$ I’m not seeing head_local or tail_local in current API specification for PoseBose. Has this been updated? $\endgroup$ Commented Oct 9, 2023 at 1:07
1
$\begingroup$

A non-python way to get the bone's head and tail, is to use snapping.
Change the snapping type to Vertex with Ctrl Shift Tab. Turn snapping on with Shift Tab, or leave it off and hold Ctrl to toggle it on during movements. Then just snap a empty to the bones. While in pose mode, just select the empty then snap it to the bone you want. Then to get the coordinates just look at the empty's location. It is at the top of the Properties panel, press N to show it.

$\endgroup$
1
  • $\begingroup$ Thanks. It doesn't appear to work on bone tails tho. Any way to get these non-programmatically? $\endgroup$
    – ecv
    Commented May 8, 2020 at 11:13

You must log in to answer this question.

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