Convert Space.
Have elaborated on your answer,
Setting an objects world matrix from a pose bone matrix is not going to work as expected when the rig object has a non identity matrix_world.
There is a convenience method on the rig object to convert a matrix from one space to another. In this case the 'POSE' space pose bone matrix, to 'WORLD' space.
M = arm.convert_space(pose_bone=bone,
matrix=bone.matrix,
from_space='POSE',
to_space='WORLD',
)
ob.matrix_world = M
A mesh object named "WORLD" is added to scene in world space.
One mesh object "POSE" is added as a child of the pose bone. Notice that bone parenting uses the tip as the origin. A parent inverse matrix has been created to make the origin of mesh appear over the head of bone.
For demo sake, have used context in this test script. Instead of hard coding names, the bone the active pose bone, the rig is the context object . (or ID object it belongs to bone.id_data
) Run the script in pose mode. As a rule of thumb if selected pose bones are of interest eg for bone in context.selected_pose_bones:
. If setting for all, object mode may be a better fit.
Test script.
import bpy
from mathutils import Matrix
context = bpy.context
scene = context.scene
arm = context.object
bone = context.active_pose_bone
# verts
height_from_bone = .2
verts = [
(0, 0, 0),
(0, 0, height_from_bone),
(0, bone.length, height_from_bone),
(0, bone.length, 0)
]
# mesh from verts
mesh = bpy.data.meshes.new('name')
mesh.from_pydata(verts, [], [])
ob = bpy.data.objects.new('name', mesh)
scene.collection.objects.link(ob)
ob.name = 'POSE'
ob.parent = arm
ob.parent_type = 'BONE'
ob.parent_bone = bone.name
ob.matrix_parent_inverse = Matrix.Translation(
verts[-1], # negate
).inverted() # or inverted
ob = ob.copy()
ob.parent = None
ob.name = 'WORLD'
M = arm.convert_space(pose_bone=bone,
matrix=bone.matrix,
from_space='POSE',
to_space='WORLD',
)
ob.matrix_world = M
scene.collection.objects.link(ob)