16

Is there a command for getting world-space matrix of pose bones, same as obj.matrix_world for objects? I found pose_bone.matrix, but it gives weird result for me.

ideasman42
  • 47,387
  • 10
  • 141
  • 223
Roman Volodin
  • 1,254
  • 2
  • 11
  • 20

3 Answers3

17

Yes:

As the documentation says, a pose bones matrix is in object space, this means - unless the object has no loc/scale/rot applied, you will have to apply the objects matrix.

matrix_final = obj.matrix_world @ pose_bone.matrix

This test script adds an empty at the pose-bone.

# Assume we are in pose mode with an active bone

import bpy from bpy import context

pose_bone = context.active_pose_bone

we can get the object from the pose bone

obj = pose_bone.id_data matrix_final = obj.matrix_world @ pose_bone.matrix

now we can view the matrix by applying it to an object

obj_empty = bpy.data.objects.new("Test", None) context.collection.objects.link(obj_empty) obj_empty.matrix_world = matrix_final

batFINGER
  • 84,216
  • 10
  • 108
  • 233
ideasman42
  • 47,387
  • 10
  • 141
  • 223
5

mathutils now uses the PEP 465 binary operator for multiplying matrices.

matrix_final = obj.matrix_world * pose_bone.matrix

becomes

matrix_final = obj.matrix_world @ pose_bone.matrix

Since 2.8 object are now stored in Collections, so :

context.scene.objects.link(obj_empty)

becomes

bpy.data.collections['Collection'].objects.link(obj_empty)

Here is the complete script updated:

# Assume we are in pose mode with an active bone,
# and a collection named collecion exist

import bpy
from bpy import context

pose_bone = context.active_pose_bone

# we can get the object from the pose bone
obj = pose_bone.id_data
matrix_final = obj.matrix_world @ pose_bone.matrix


# now we can view the matrix by applying it to an object
obj_empty = bpy.data.objects.new("Test", None)
bpy.data.collections['Collection'].objects.link(obj_empty)
obj_empty.matrix_world = matrix_final
Leander
  • 26,725
  • 2
  • 44
  • 105
pidou46
  • 51
  • 1
  • 1
  • Thanks, this is useful ! But now I would like to ask, I have global_matrix, how to convert it to localtransform (localtion / rotation / scale)? – user66174 Mar 13 '20 at 16:00
4

Again with tip to tail offset.

Slight addition to @ideasman42's answer to enable globally locating to tip or tail of bone based on an offset. 0 is as above at fat end of bone (head), 1 at skinny end (tail).

This is to emulate somewhat the option in copy transform constraints to locate with offset along bone.

The vector

(pb.head - pb.tail)

describes the object space vector from head to tail A translation matrix is created to translate point of interest locally along the bone.

# Assume we are in pose mode with an active bone

import bpy from bpy import context from mathutils import Matrix

add empty half way along bone

offset = 0.5 # 0 for tail 1 for tip.

pb = context.active_pose_bone

T = Matrix.Translation( offset * (pb.tail - pb.head) )

we can get the object from the pose bone

obj = pb.id_data matrix_final = obj.matrix_world @ (T @ pb.matrix)

now we can view the matrix by applying it to an object

obj_empty = bpy.data.objects.new("Test", None) context.collection.objects.link(obj_empty) obj_empty.matrix_world = matrix_final

batFINGER
  • 84,216
  • 10
  • 108
  • 233