7

I use the below code to retrieve location of pose.bone, but it always give 0 (or -0).
It seems the pose.bone location is the relative position of its parent so it will not-zero value once I grab pose.bone to somewhere?!
Is there a way to get "global location(X, Y, Z)" of pose.bone??

for action in bpy.data.actions:
    print(action)
    for fcurve in action.fcurves:
         print("data_path:" + fcurve.data_path + ", channel " + str(fcurve.array_index))
         for keyframe in fcurve.keyframe_points:
              print(keyframe.co)

 

data_path:pose.bones["Bone.011"].location, channel 0 
Vector (13.0000, -0.0000) 
Vector (29.0000, -0.0000) 
Vector (40.0000, -0.0000) 
Vector (45.0000, -0.0000) 
Vector (83.0000, -0.0000) 
Vector (110.0000, -0.0000) 
data_path:pose.bones["Bone.011"].location, channel 1 
Vector (13.0000, 0.0000) 
Vector (29.0000, 0.0000) 
Vector (40.0000, 0.0000) 
Vector (45.0000, 0.0000) 
Vector (83.0000, 0.0000) 
Vector (110.0000, 0.0000) 
data_path:pose.bones["Bone.011"].location, channel 2 
Vector (13.0000, -0.0000) 
Vector (29.0000, -0.0000) 
Vector (40.0000, -0.0000) 
Vector (45.0000, -0.0000) 
Vector (83.0000, -0.0000) 
Vector (110.0000, -0.0000) 
data_path:location, channel 0 
Vector (13.0000, 0.0245) 
Vector (45.0000, -3.3037) 
Vector (83.0000, 0.0245) 
Vector (110.0000, 1.5101) 
data_path:location, channel 1 
Vector (13.0000, -0.0075) 
Vector (45.0000, -0.0075) 
Vector (83.0000, -0.0075) 
Vector (110.0000, -0.0075) 
data_path:location, channel 2 
Vector (13.0000, 3.0031) 
Vector (45.0000, 2.5048) 
Vector (83.0000, 1.8442) 
Vector (110.0000, 1.8442) 
gandalf3
  • 157,169
  • 58
  • 601
  • 1,133
Caxton
  • 73
  • 1
  • 4

2 Answers2

8

This is a bit of a duplicate of this question, but just to complete the picture, to get the global location of your pose bone, you need to multiply the bone's location by the armature and the bone's transform matrices (sounds complicated, but is actually simple):

p = bpy.context.active_pose_bone  # Our pose bone
o = bpy.context.object            # Our armature object
global_location = o.matrix_world * p.matrix * p.location
TLousky
  • 16,043
  • 1
  • 40
  • 72
  • 1
    but how if the p.location is 0? then the global_location is always 0? – Caxton Aug 20 '15 at 08:02
  • Not an expert in linear algebra, but from what I understand, not necessarily: http://mathinsight.org/matrix_vector_multiplication – TLousky Aug 20 '15 at 09:03
  • not sure about what "not necessarily" mean.. do you mean value of p.location is 0 will not result in global_location to 0? – Caxton Aug 21 '15 at 04:28
  • 2
    Yes, it depends on the transform matrices of the armature and the p's parent bones, both represented in the aforementioned code. – TLousky Aug 21 '15 at 05:49
1

If anyone is interested in a more declarative approach, the following did the trick for me. For a given animation, this snippet retrieves the global 3D position of each bone (head and tail) as well as the pixel+depth position with respect to the camera:

from bpy_extras.object_utils import world_to_camera_view

armature = ... cam = ...

pose_bones = {pb.name: pb for pb in D.objects[armature.name].pose.bones} for frame_i in range(C.scene.frame_start, C.scene.frame_end + 1): print("Collecting positions for frame >>>", frame_i) # C.scene.frame_current = frame_i bpy.context.scene.frame_set(frame_i) # important: refresh scene between frames data = {"frame": frame_i} for ico_bone, ico in icospheres: # get PoseBone global position pb_tail = pose_bones[ico_bone].tail pb_head = pose_bones[ico_bone].head # get PoseBone cam-relative position (0,0)=bottom left, (1,1)=top right pb_tail_cam_xyz = world_to_camera_view(C.scene, cam, pb_tail) pb_head_cam_xyz = world_to_camera_view(C.scene, cam, pb_head)

The approach is based on the following observation:

At a given frame,the head and tail fields of the D.objects[armature.name].pose.bones show the current global position in (x, y, z) coordinates.

I've tested it on 2.90 and seems to work fine, please correct me otherwise! Hope this helps.

Cheers,
Andres

fr_andres
  • 521
  • 6
  • 11