I've been using an old script for a long time to import a custom format which contains a 4x4 matrix for the bone transform (inverted) and 4x3 for the bone animation (3x3 rotation matrix + 1 location vector).
In the recent versions of blender, "bone.matrix" was read_only. So I decided to stick with my v2.49 script for the mean time. But, I recently noticed an update with the blender API that the "bone.matrix" is no longer read only. So, I decided to rewrite my old script to the latest API (not really rewrite as I script it from scratch, just used the old script as reference).
Now, with my new script completed, 2 problem arises.
- Bone's aren't set right.
- Animation is messed-up.
As for the first problem, I find it really odd. Let me show you the related codes:
In the old script, setting the "bone.matrix" was done, simply, like this:
bone.matrix=Matrix4x4(g.f(16)).invert()
bvec = bone.tail- bone.head
bvec.normalize()
bone.tail = bone.head + 0.01 * bvec
And that worked well. As for the new script, I did it in a very identical way (I think)
bone_matrix = struct.unpack("<ffffffffffffffff", fObj.read(64))
bone_imatrix = mathutils.Matrix((bone_matrix[0:4],\
bone_matrix[4:8],\
bone_matrix[8:12],\
bone_matrix[12:16])).inverted()
bone.matrix = bone_imatrix[0:16]
bone.tail = bone.head + 0.01 * bone.vector
But here is where things gets weird... To my knowledge the 2 codes above are completely identical but the resulting data is quite different.
How different? When I try to check some values via the console, I get this:
# OLD SCRIPT
>>> bpy.data.objects["armature"].data.edit_bones["0"].matrix
Matrix(((-4.371138828673793e-08, 0.0, 1.0, 0.0),
(0.0, 0.9999999403953552, 0.0, 1.9815000295639038),
(-1.0, 0.0, -4.371138828673793e-08, -0.54830002784729),
(0.0, 0.0, 0.0, 1.0)))
>>> bpy.data.objects["armature"].data.edit_bones["0"].head
Vector((0.0, 1.9815000295639038, -0.54830002784729))
>>> bpy.data.objects["armature"].data.edit_bones["0"].tail
Vector((0.0, 2.0815000534057617, -0.54830002784729))
>>> bpy.data.objects["armature"].data.edit_bones["0"].matrix.decompose()
(Vector((0.0, 1.9815000295639038, -0.54830002784729)), Quaternion((0.7071068286895752, 0.0, 0.7071068286895752, 0.0)), Vector((1.0, 0.9999999403953552, 1.0)))
# NEW SCRIPT
>>> bpy.data.objects["rig_0"].data.edit_bones["bone_0"].matrix
Matrix(((-4.371138828673793e-08, 0.0, 1.0, -0.0),
(-1.0, 0.0, -4.371138828673793e-08, 1.9815000295639038),
(0.0, -0.9999999403953552, 0.0, -0.54830002784729),
(0.0, 0.0, 0.0, 1.0)))
>>> bpy.data.objects["rig_0"].data.edit_bones["bone_0"].head
Vector((-0.0, 1.9815000295639038, -0.54830002784729))
>>> bpy.data.objects["rig_0"].data.edit_bones["bone_0"].head
Vector((-0.0, 1.9815000295639038, -0.54830002784729))
>>> bpy.data.objects["rig_0"].data.edit_bones["bone_0"].matrix.decompose()
(Vector((-0.0, 1.9815000295639038, -0.54830002784729)), Quaternion((0.5, -0.5, 0.5000000596046448, -0.5000000596046448)), Vector((1.0, 0.9999999403953552, 1.0)))
Noticed that the quaternions from the decompose are different? That is my first question, why did this happen? What did I do wrong?
Moving on to my second problem, the messed-up animation. I believe this problem is a side-effect of the 1st problem. But I'm not entirely sure. So, I'll just share some info about it. (just in case the first problem doesn't have anything to do with the second problem)
On my old script, I did the animation like this:
matrix=Matrix3x3(g.f(9)).resize4x4()
pos=g.f(3)
matrix=matrix*VectorMatrix(pos)
boneMatrix=Blender.Object.Get('armature').getData().bones[str(k)].matrix['ARMATURESPACE']
# ...some other part
pbone=pose.bones[name]
pbone.poseMatrix=boneMatrix*matrix
pbone.insertKey(skeleton, 1+frame,\
[Blender.Object.Pose.ROT,Blender.Object.Pose.LOC],True)
pose.update()
I think my code is quite similar but I'm no expert. Here is my new script:
name = "bone_%d" % bi
bone = rig.data.bones[name]
pbone = rig.pose.bones[name]
rot_matrix = struct.unpack("<fffffffff", fAni.read(36))
rot_matrix = mathutils.Matrix((rot_matrix[0:3],\
rot_matrix[3:6],\
rot_matrix[6:9]))
rot_matrix.resize_4x4()
loc_vector = struct.unpack("<fff", fAni.read(12))
loc_vector = mathutils.Vector( loc_vector[0:3] )
loc_matrix = mathutils.Matrix.Translation(loc_vector)
matrix = rot_matrix * loc_matrix
pbone.matrix = bone.matrix_local * matrix
pbone.keyframe_insert(
data_path = "rotation_quaternion",
frame = 1 + f,
group = name)
pbone.keyframe_insert(
data_path = "location",
frame = 1 + f,
group = name)
I have been trying to make this work for a week and I'm already going in circles, I just can't figure it out. Hopefully someone here can enlighten me.
Cheers!