Blender Python, getting delta location in bone local space

Hello guys;

i need to retrieve the DELTA_LOC of a bone that is being affected by “copy_location_constraint”;

example: i have bone 1 that has this constraint affecting it (in the UI panel the transform of this bone are still 0,0,0; it’s only moving thanks to the constraint); the datapath of the X location of bone1 (for example) will always be 0 since that value is 0; but if i use a driver to fish the actual DELTA_LOC by using the transform channel > X location > local space; my var is actually equal to something other than 0

tldr i need to know within python how to get this “var” value that drivers uses

worst case scenario i’ll build some roundabout to print this values on some custom property or other object location vector to then retrieve with python; but i’d like a cleaner way to directly fish them instead

tnx in advance

Could you share a sample file?

try.blend (3.4 MB)

here; the bone “DEF.Leg.L.001” has a copy location constraint with some other random boneand i want to know its delta_loc in local spacerelative to it itself as if it was picked by the transform channel of a driver set up; there’s some try in the text datablock that doesn’t work + other scripts that are for something else

OK… Seeing the file I suspect there must be some XY problem. I am not really an expert in rigging, but… that’s not how armatures should look. You are doing something weird here. I would guess there is probably a better way to reach the original goal.

Regarding the question asked… You copy the location of an object, so, that’s what the location is. Get it from the object you copy it from. If you need it in local space of something, you multiply inverted matrix of that something by the vector. So if I had an Empty and a Plane in my scene and I would want to get the location of the empty in my plane’s local space, I would do this:

LocationInLocalSpace-

import bpy

plane = bpy.data.objects["Plane"]
empty = bpy.data.objects["Empty"]

plane.data.vertices[0].co = plane.matrix_world.inverted() @ empty.location

So that should work for you as well, I just have no idea what is going on in that file, because… well, because of what mess it is :laughing: and I don’t really understand what kind of local space you want the location in.

explained better:
if go to add any driver in any location (this isn’t the important part), and u go to the variable box fo the blender driver, set the variable to transform channel object source: ur rig, subtarget: a bone: source fo the transformation X_location and set the space to LOCAL

now whatever var is equal to is what i need to know

explanation of the roundabout: create on each bone 3 custom properties (X , Y , Z) add to each a driver that source me with the delta_x (and then y and z) in local space; so now i’d have all 3 sources exposed BUT i’d like to try to get them directly with python without further set up;
i’m making some background handlers that update the bone position at each frame depending on the position of some other bone

EDIT: u should try to use it with the bones, because some code avaiable for objects isn’t avaiable for bones; at least i got this as far as my researches lead to

ps about the file just look at 2 random bones i’m still working over it rn so didn’t made a dummy with 2 bones

image

u’r line, i took the inverted matrix of the bone in world space and @ the bone location

as you can see this picture above is if i apply the constraint; the numbers don’t match at all

Handlers are awesome. I would try to use something else before jumping to them. Scripted drivers maybe?..

I am not sure I understand the issue. If it can be transformed, it probably has a matrix. Bones have matrices:

Bones local space is bone.matrix_local as far as I understand. :man_shrugging:

Drivers expression text box Is too small for me,

Also matrix_local doesn’t exist in pose One, but only in databone,

matrix_local = head_local (head offset relative to armature)

In posebone:

Matrix = final Matrix in world

Matrix_basis = bone transform space aka constraint and parenting are not considered

Matrix_channel = offset of the bone from it’s own rest position using world space coordinates due to having the same delta between 2 pair samples as matrix

Example setup.blend (470.5 KB)

so i made a quick example set up, since it wasn’t clear:
constrained bone has the copy constraint that put it on the head of Root bone
on result bone location vector i used driver to show the results i’m trying to search; while constrained bone transform space vector is 0,0,0 (as show with posebone.matrix_basis) it’s final position is changed; now as i explained:
matrix = final position in armature space
matrix_channel = offset of the bone from its rest position
matrix_basis = transform space (u can affect this via manual moving, drivers, anything that can directly change the vector location in the N panel)

databones.matrix_local (bpy.data.armatures.bone.matrix_local) gives u armature data in rest pose (?!? forgot the right term) btw databones.matrix_local is equal to this line (for translation vector) bpy.data.armatures.bone.head_local

tldr the data from drivers that uses transform channel local space is “hidden” with some mathematical operation and is not a single line that gives u matrix that is the local space offset

Scripted drivers. I meant those. There may be unforeseen issues with handlers, I think it might be better to use drivers, they are designed for this. But… Sure, if you have no problems with handlers, you have no problems with handlers, I guess. Drivers are meant to be better suited for this. :man_shrugging: Not sure if they would be, just something to consider.

I am not familiar with all the structures in bones, but I’ll have a look if I can understand the issue in the simplified file and figure this out.

Edit: Nope. Sorry, I really don’t understand what you want to do here and why. Maybe someone else more experienced with rigging can help. I just don’t understand the problem needed to solve here and the context at all.

problem is mainly with the text box and multitude of variable;
1.i have 540 bone
2.each bone has a driver/handler (basically automatic input data) on both X and Y
3.each bone follows a segmented path (polyline) and the “magnitude” of how much it travel is according to the rotation of the leg
4.bones near the hips have 10 segments, while further away have not even a full segment
5. each segmented path is different for each bone and it depend on the bone surrunding itself

tldr implementing a driver like this manually without proper python loops is crazy; and the expression handling all this variables is 5 times longer than the maximum character allowed in the text box; so a good solution was falling back on handlers

so far so good if stress tested them a bunch of times without failures

anyway tnx anyway for trying to help, here i used this reply to try to respond to your curiousity of wh handlers over drivers, now i’ll just post another reply to the main thread with the answer i came up with, that was the answer i was searching if someone else also may need it,

cya o/

import bpy

posebones = bpy.data.objects[“Armature”].pose.bones[“Constrained Bone”]
databones = bpy.data.armatures[“Armature”].bones[“Constrained Bone”]

delta in local space with no parent transformation

local_space = posebones.matrix_channel.to_4x4() @ databones.matrix.to_4x4()

print(f’local_space == {local_space.to_translation()}')

parent delta offset

parent_offset = databones.parent.matrix.to_4x4().inverted() @ posebones.parent.matrix_channel.to_4x4()

print(f’parent_offset == {parent_offset.to_translation()}')

final delta_loc of the constrained bone

delta_loc = parent_offset.inverted() @ local_space

print(f’delta_loc == {delta_loc.to_translation()}')

i don’t understand how matrices works, but i got a decent understanding of what the lines means in the API; also attaching a blender example file so ppl can play around and see if it works for them too

Example setup.blend (527.7 KB)