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?
3 Answers
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.
The answer by @David does not look okay to me. I might be wrong.
- The
context.active_pose_bone.tail
gives us location with respect to the parent bone. - 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]]
-
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
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.
-
$\begingroup$ Thanks. It doesn't appear to work on bone tails tho. Any way to get these non-programmatically? $\endgroup$– ecvCommented May 8, 2020 at 11:13