1
$\begingroup$

I'm trying to create a script that will place two vertices onto a bone, one at the head and one at the tail, and then translate them above the bone so that they are in line with rotation of the bone's pose position. I am able to place the vertices, but can't figure out how to translate them correctly.

Here is an example of what I'm trying to do:

Before

enter image description here

After

enter image description here

$\endgroup$

2 Answers 2

2
$\begingroup$

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)
$\endgroup$
2
  • $\begingroup$ Thank you for the information. Your script seems to work for my case. Could you tell me why the rig object might have a 'non identity matrix_world'? I'm not quite sure what this means. $\endgroup$
    – hilifit
    Commented Aug 24, 2021 at 12:57
  • 1
    $\begingroup$ ie not at zero location (0, 0, 0) and rotation and unit scale (1, 1, 1). If it is then the local space will match global The matrix is used in conversion from local to global space. When it is identity it has no effect on calculation, like multiplying by 1. To test Move the rig object and run scripts to see difference. BTW this blender.stackexchange.com/a/119342/15543 may come into play with non uniform pose bone scaling. $\endgroup$
    – batFINGER
    Commented Aug 24, 2021 at 13:01
1
$\begingroup$

Okay I figured it out.

# get bone
arm = bpy.data.objects['Armature']
bone = arm.pose.bones['Bone']

# verts
height_from_bone = .5
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)
bpy.context.scene.collection.objects.link(ob)

# apply bone matrix
ob.matrix_world = bone.matrix

# delete verts as necessary...

The first vertex in the list is the origin of the mesh object and will be located at the head of the bone when the bone matrix is applied to the mesh object.

$\endgroup$

You must log in to answer this question.

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