1
$\begingroup$

Could someone help me get out of the starting blocks I suspect I'm making this harder than it needs to be.

with python

Lets say in pose mode I have bone A at location (0.00,0.00,2.00) world space equivalent local space is (0.00,0.00,0.00) I want to move it to the same location as bone B in the same local space. Lets say bone B is at (0.00,1.00,0.00) world space local space is (0.00,0.00,0.00)

I've been going around in circles with various matrix calculations and Just can't get my head around it just yet. The local space for bone A in this example should end up as (0.00,-2.00,-1.00)

I found this in relation to a different question which has a great answer and explains how the matrices are set up clearly but I can't seem to apply it to my situation. How to convert coordinates from vertex to world-space?

thanks!

Mark

$\endgroup$
  • $\begingroup$ Related Also look at the addons/rigify/rig_ui_template.py Visual Helper functions. $\endgroup$ – batFINGER Jan 28 '18 at 9:36
  • $\begingroup$ thanks so much, that got me on the right lines, will post code snippet $\endgroup$ – Mark Jan 28 '18 at 10:33
0
$\begingroup$

Many thanks @batFINGER that got me heading in the correct direction, I now need to spend a few hours understanding why it works :) I modified the code from the example you linked to.

I've updated with extra comments and modified the code after I did some research to get my head around it, happy to take feed back I've misinterpreted anything

does not seem to need any additional calculations if it's a child of another bone but would be interested I'f I missed something there.

Mark

In my example from my question

  • bone y+1 is located at (0,1,0) in pose space but the local location is (0,0,0) as that is where the bone is in edit mode.
  • bone z+2 is located at (0,0,2) in pose space but it's local location is (0,0,0) as that is where the bone is in edit mode.
  • the armature object is at (0,0,0) world space

The translation (where the bone actually is in pose space) is stored in the first 3 rows of the 4th column of the 4x4 matrix reading down X,Y Z the other numbers define rotation and scale which I'm not looking at here.

so for y+1 the default matrix is
(1.0000, 0.0000,  0.0000, 0.0000)
(0.0000, 0.0000, -1.0000, 1.0000)
(0.0000, 1.0000,  0.0000, 0.0000)
(0.0000, 0.0000,  0.0000, 1.0000)

for z+2 the default matrix is
(1.0000, 0.0000,  0.0000, 0.0000)
(0.0000, 0.0000, -1.0000, 0.0000)
(0.0000, 1.0000,  0.0000, 2.0000)
(0.0000, 0.0000,  0.0000, 1.0000)

the armature world matrix is
(1.0000, 0.0000, 0.0000, 0.0000)
(0.0000, 1.0000, 0.0000, 0.0000)
(0.0000, 0.0000, 1.0000, 0.0000)
(0.0000, 0.0000, 0.0000, 1.0000)

The armature world matrix is important if you want to translate locations between world and local space as if it's not (0,0,0) then it needs to be added as an offset (and removed as an offset (inverted) as required.)

import bpy

#assume armature is active and has 2 bones in it called
# "y+1" and "z+2" at different locations
armature = bpy.context.active_object
y1_bone = armature.pose.bones["y+1"]
z2_bone = armature.pose.bones["z+2"]

#y1 is the bone we want to use as the target,
#multiplying 2 matrices is a dot multiplication i.e. each column gets multiplied with each row then added together
#it's not simple scalar with one value with just multiply the whole matrix so the below will produce a matrix 
#that will add the armature world location to the y1 location

#if you want to place or align stuff outside the armature in world space then the following two pieces of code will 
#take the armature world space offset into account but it's over kill for just moving about in the same local space

#this gets the world space
y1_world_matrix = armature.matrix_world * y1_bone.matrix

#this copies the default and calculates the local space
matrix = armature.matrix_world.inverted() * y1_world_matrix

#the above two would make more sense if say you were trying to place an
#empty in world space at the pose bones location.
z2_bone.matrix.translation = matrix.translation


#if it's just in local space you can remove the armature offset calculations 
#above and just assign the translation
#of the target bone to the bone you want to move
#e.g. the below and the local space coordinates will update accordingly.

z2_bone.matrix.translation = y1_bone.matrix.translation
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.