Home Technical Talk

Blender 2.8 | Snap bone in pose mode to empty location

polycounter lvl 10
Offline / Send Message
Blendermonkey polycounter lvl 10
Hi,
I'm trying to make a world space to pose space converter. Ex: IK arm ctrl is in world space. I switch to hip space and the arm doesn't pop out but stays in the place it was before.

I do this by spawning an empty at the bone location, switching space and moving the bone to the empty. But I can't move it back correctly.

As you see I tried to move two bones, and they don’t end up at the same location. My guess is that I’m not grabbing the the right location vector. But I’m not quite sure how to do this.

To test: spawn an armature, extrude a bone and disconnect it. Also, add one empty. Then the script should work.

import bpy <br>from bpy import context <br>armature = "Armature" <br>pose_bone = context.active_pose_bone <br>obj_empty = bpy.data.objects["Empty"].location <br>tst = bpy.data.objects[armature].matrix_world.inverted() <br>loc = tst @ obj_empty <br>bpy.data.objects[armature].pose.bones["Bone.001"].location = loc <br>bpy.data.objects[armature].pose.bones["Bone"].location = loc<br><br>print(obj_empty)&nbsp;<br>print (loc)&nbsp;<br>print (tst)&nbsp;<br><br>

This is urgent for me so any help is highly appreciated. Thank you for reading!

Replies

  • RN
    Options
    Offline / Send Message
    RN sublime tool
    Have you tried the .head or .tail attributes of pose bones?
    https://docs.blender.org/api/2.79/bpy.types.PoseBone.html#bpy.types.PoseBone.head

    Get the pose-space 'offset' vector from head to tail, reposition the head to 'loc' and the tail to 'loc + offset', is what I'd try.
  • RN
    Options
    Offline / Send Message
    RN sublime tool
    Hm, actually let me amend that, .head and .tail are for the Edit mode bone data, not for Pose mode like you want.

    There's something here:
    - When you extrude a bone, even if you disconnect it, it still remains parented to the bone it was extruded from.
    This means that 'loc' vector would be interpreted as being in local-space to that extruded bone.
    So something like (0,0,0), in the space of "Bone.001", means its edit-mode (also called "bind pose") location, not its pose-space location.

    The transform matrices of all bones are in pose-space (even in a huge hierarchy), so you can translate them this way:
    import bpy<br>armature = bpy.data.objects["Armature"]<br>bones = armature.pose.bones<br><br>worldEmptyPos = bpy.data.objects["Empty"].matrix_world.col[3] # 4D translation.<br>poseEmptyPos = armature.matrix_world.inverted() * worldEmptyPos<br><br>bones["Bone"].matrix.col[3] = poseEmptyPos<br>bones["Bone.001"].matrix.col[3] = bones["Bone"].matrix.col[3] # Using this instead of 'poseEmptyPos' or we get weird behavior (?)<br><br>


  • Blendermonkey
    Options
    Offline / Send Message
    Blendermonkey polycounter lvl 10
    RN said:
    Hm, actually let me amend that, .head and .tail are for the Edit mode bone data, not for Pose mode like you want.

    There's something here:
    - When you extrude a bone, even if you disconnect it, it still remains parented to the bone it was extruded from.
    This means that 'loc' vector would be interpreted as being in local-space to that extruded bone.
    So something like (0,0,0), in the space of "Bone.001", means its edit-mode (also called "bind pose") location, not its pose-space location.

    The transform matrices of all bones are in pose-space (even in a huge hierarchy), so you can translate them this way:
    import bpy<br>armature = bpy.data.objects["Armature"]<br>bones = armature.pose.bones<br><br>worldEmptyPos = bpy.data.objects["Empty"].matrix_world.col[3] # 4D translation.<br>poseEmptyPos = armature.matrix_world.inverted() * worldEmptyPos<br><br>bones["Bone"].matrix.col[3] = poseEmptyPos<br>bones["Bone.001"].matrix.col[3] = bones["Bone"].matrix.col[3] # Using this instead of 'poseEmptyPos' or we get weird behavior (?)<br><br>


    Thanks, This worked like a charm! However this doesn't work if the bone has a ChildOf contraint on it. Then it is moved to the empty but with an offset. How would I account for the offset and counter it?
  • RN
    Options
    Offline / Send Message
    RN sublime tool
    Hm, that's interesting.

    I had to look in the API docs to see any alternatives.
    It seems boy.types.PoseBone.matrix is the pose-space matrix with constraints already applied, so any changes happen after the contribution of any constraints.
    Try replacing the 'matrix' usage with 'matrix_channel', a different attribute:
    https://docs.blender.org/api/2.79/bpy.types.PoseBone.html#bpy.types.PoseBone.matrix_channel

Sign In or Register to comment.