how to position a bone in world space?

as far as I know you can only change the position of a bone using bone.location, which is in local coordinates. how do I set the position of a bone to match the position of a game object?

Integrate it to armature’s world position.

I kind of see where you’re going with this, can you give me something a little more specific/more details? thanks

I should say, this is for a humanoid armature rig, and I need to set the position of all bones (making a ragdoll setup and I have the ragdoll physics working, now I need to set the armatures bones to copy the location, rotation of the rigid body bounding objects)

bonePos = bone.pose_head+armature.worldPosition

Assuming that the bone’s head is it’s origin, if you want it’s middle as origin use:

bonePos = (bone.pose_head + bone.pose_tail)/2 + armature.worldPosition

ok that should return the bone’s world position, cool, how do I set the bone’s world position now?

tested this out and it does indeed give me the bone’s world position, very cool, but what I really want is to be able to set the actual bone to the world position of another object

The bone position is in armature space, so you’d want to convert your desired position to armature space too.


desiredPos = desiredObject.worldPosition - armature.worldPosition
bone.pose_head = desiredPosition

import bge
from mathutils import Quaternion, Vector, Matrix




def get_bone_pose_matrix_cleaned(bone):
    # note that lack the scale (i'm not sure how make it)
    offset_m4 = (Matrix.Translation(bone.location) * Quaternion(bone.rotation_quaternion).to_matrix().to_4x4())
    return bone.pose_matrix * offset_m4.inverted()
    
def set_bone_world_position(bone, arm, worldPosition):
    bone.location = get_bone_pose_matrix_cleaned(bone).inverted() * arm.worldTransform.inverted() * worldPosition
    




def main():
    cont = bge.logic.getCurrentController()
    arm = cont.owner
    bone = arm.channels["Bone.003"]
    target = arm.scene.objects["Target"]
    
    set_bone_world_position(bone, arm, target.worldPosition)
    arm.update()


main()

It’s ok if it lacks scale, it does include rotation though? I’ll have a chance to try it out later. thanks a lot by the way I really appreciate the help

ok see this is exactly what i was trying to figure out how to do, thanks, and the functions you wrote, it looks like that incorporates rotation as well?

it works! awesome! I think setting the rotation after the location should be easy, I’m gonna try that later when I have time, but thank you so much for creating this, I couldn’t have done it myself. once I have the setup working properly I’ll post the .blend so you can check it out, I may need help setting the rotation, I’ll try and see if I can do it later

ok so it turns out setting the orientation of the bone isn’t that simple, I tried
bone.joint_rotation = ‘bone bounding box’.worldOrientation.to_euler()
and
bone.rotation_euler = ‘bone bounding box’.worldOrientation.to_euler()

the syntax is correct and it does manipulate the bone’s orientation but it doesn’t align the bone correctly to it’s respective bounding object and it behaves oddly

afaik not exist the “world space” for the bones , for that you have to do “some” trasformations .

to copy also the rotation there to change a bit the function , and copy both, position and rotation:

import bge
from mathutils import Quaternion, Vector, Matrix








def get_bone_pose_matrix_cleaned(bone):
    # note that lack the scale (i'm not sure how make it)
    offset_m4 = (Matrix.Translation(bone.location) * Quaternion(bone.rotation_quaternion).to_matrix().to_4x4())
    return bone.pose_matrix * offset_m4.inverted()
    
def set_bone_world_position(bone, arm, worldPosition):
    bone.location = get_bone_pose_matrix_cleaned(bone).inverted() * arm.worldTransform.inverted() * worldPosition
    
def set_bone_world_position_and_orientation(bone, arm, world_m4_to_copy):
    new_offset = get_bone_pose_matrix_cleaned(bone).inverted() * arm.worldTransform.inverted() * world_m4_to_copy
    p,q,s = new_offset.decompose()
    bone.location = p
    bone.rotation_quaternion = q
    








def main():
    cont = bge.logic.getCurrentController()
    arm = cont.owner
    bone = arm.channels["Bone.003"]
    target = arm.scene.objects["Target"]
    
    #set_bone_world_position(bone, arm, target.worldPosition)
    set_bone_world_position_and_orientation(bone, arm, target.worldTransform)
    arm.update()








main()





anyway , you know that you can use “copy transform” in the UI bone constraint?

to copy another gameobject seem more easy.

yeah, you just have to run the armature to update the constraints :smiley:

as far as easy goes, the script is plenty easy to use and I prefer to use it, however, it’s very cpu intensive because I have to run the script every frame to keep the bones in place smoothly and that’s a lot of math to run every frame (a for loop iterates through the bones and sets them in place every frame). I’ll set up the entire rig with constraints and see if the performance is better than using the script. Very impressive code btw

ok so it turns out I still have a really good use for your script, I modified it to just print out each bone’s orientation and position to the console. it prints out the static transforms of the bones. In the 3D view, I take a bounding object, set it to the transforms that I printed out and that way I can set up the bounding objects to perfectly match the armatures pose because when the game is ran, the bones will match the transforms of the bounding objects, and I want them to retain the initial pose of the armature. Thanks so much for your help, and thanks Jacob for the tip. I’ll set this thread to solved, still have quite a bit of work to do setting this up and when I’m happy with it I’ll post a blend. Thanks again for all the help

how could this rotation be applied to a specific axis of the bone?