I have looked at the other questions that have been posted here and I am very sorry that this is such a similar question AGAIN but none of the issues solved it for my issue.
I am working on an application that converts 3d joint positions into an animation with the goal of saving the deformed mesh at certain points.
What I have right now is a mesh, an armature that is properly parented to it (I checked in pose mode) and all the 3d joint positions. What I would like to do now is "just" move the heads and tails of the bones (in edit/object/pose mode, whichever gives me a deformed mesh to export) to the correct position with a python script and then export the deformed mesh.
However, while I can change the armature in edit mode by positioning heads and tails of the
edit_bones, the mesh stays the same (duh) and in pose mode I can only set the location of the entire
pose_bone, heads and tails are read only. I would like to avoid the hassle of computing translation matrices, rotation matrices and scale factors for every joint - am I missing something?
It feels like I am so close to the solution and yet I can't progress.
Code version 1
Code with pose mode (the way I understand it this should move all bones randomly but the actual result is it just moves the root node and and therefore the whole mesh, all joints stay in the same relative position to the root node. If I try to move only the nose for example nothing happens but the
pose_bone.location changes, maybe I am missing the
bpy.context.scene.update() from the example but it causes an attribute error for me) as per this solution on stackexchange
import bpy import numpy as np import mathutils import random from bpy import context bpy.ops.object.mode_set(mode='POSE') armature = bpy.context.scene.objects['Armature'] for pose_bone in armature.pose.bones: print(pose_bone.location) x = pose_bone.location + random.uniform(-0.2, 0.2) y = pose_bone.location + random.uniform(-0.2, 0.2) z = pose_bone.location + random.uniform(-0.2, 0.2) pose_bone.location = x pose_bone.location = y pose_bone.location = z print(pose_bone.location) print('changed' + pose_bone.name)
Instead of directly assigning the coordinates i also tried this
bone.location = armature.matrix_world.inverted() @ bone.bone.matrix_local.inverted() @ v in case there was an issue with coordinate systems but the result is the same, I cannot independently move individual bones.
Update on the pose mode solution: it seems like the issue was setting the location, this only works for my root node, the location change is ignored everywhere else (why is the functionality provided for non root bones then ?).
What does work is setting the rotation of individual bones but that brings me back to the problem that i would have to compute the rotation matrices (and potential scaling) for every frame of my data, which will probably result in errors at the ends of the limbs because of accumulating errors.
Code version 2
This version is in Edit Mode and changes heads and tails of the armature bones but the mesh remains unchanged (per this solution)
import bpy import numpy as np import mathutils import random as rd from bpy import context bpy.ops.object.mode_set(mode='EDIT') obj = context.object for bone in obj.data.edit_bones: random_vector_1 = mathutils.Vector((rd.uniform(-0.2, 0.2), rd.uniform(-0.2, 0.2), rd.uniform(-0.2, 0.2))) bone.head += random_vector_1 random_vector_2 = mathutils.Vector((rd.uniform(-0.2, 0.2), rd.uniform(-0.2, 0.2), rd.uniform(-0.2, 0.2))) bone.tail += random_vector_2