Hey everyone,
I’m writing an exporter and need to rotate the bone matrices so that Y is up. This is some code that has (I’m fairly sure) worked in the past with v2.70. But now with v4.0, it tells me the matrix has no inverse.
Can anyone see anything obvious wrong with my code?
def convertBoneMatrix(self, pose_bone):
matrix = pose_bone.matrix.copy()
if not pose_bone.parent:
matrix = matrix * Matrix.Rotation(1.5707963267948966, 4, 'Z')
else:
parent_matrix = pose_bone.parent.matrix
matrix = (parent_matrix * Matrix.Rotation(1.5707963267948966, 4, 'Z')).invert() * matrix * Matrix.Rotation(1.5707963267948966, 4, 'Z')#Fails here
matrix.transpose()
return matrix
Any further information needed please don’t hesitate to ask. Thankyou.
It appears that Matrix.invert() does not return a value… so
Matrix.Rotation(...).invert() * another_matrix
is meaningless.
>>> m = Matrix.Rotation(pi/2, 4, 'Z')
>>> m
Matrix(((7.549790126404332e-08, -1.0, 0.0, 0.0),
(1.0, 7.549790126404332e-08, 0.0, 0.0),
(0.0, 0.0, 1.0, 0.0),
(0.0, 0.0, 0.0, 1.0)))
>>> m.invert()
>>> m
Matrix(((7.549790126404332e-08, 1.0, 0.0, -0.0),
(-1.0, 7.549790126404332e-08, -0.0, 0.0),
(0.0, -0.0, 1.0, -0.0),
(-0.0, 0.0, -0.0, 1.0)))
>>> m.invert()
>>> mi = m.invert()
>>> mi #### this returns nothing
>>> m * mi
Traceback (most recent call last):
File "<blender_console>", line 1, in <module>
TypeError: Element-wise multiplication: not supported between 'Matrix' and 'NoneType' types
To fix your code, get the Matrix.invert() step out of the math equation. Put the .invert() call on a separate line of code.
Ah of course. Thanks. It still fails with the same error though.
def convertBoneMatrix(self, pose_bone):
matrix = pose_bone.matrix.copy()
if not pose_bone.parent:
matrix = matrix * Matrix.Rotation(1.5707963267948966, 4, 'Z')
else:
parent_matrix = pose_bone.parent.matrix
matrix = parent_matrix * Matrix.Rotation(1.5707963267948966, 4, 'Z')
matrix.invert()#Fails here
matrix = matrix * Matrix.Rotation(1.5707963267948966, 4, 'Z')
matrix.transpose()
return matrix
Next, I would advise you to print out parent_matrix. I can’t do that for you…
Matrix.Rotation(pi/2, 4, ‘Z’) is invertible… so the problem has to be parent_matrix, or the result of the multiplication.
Matrix multiplication is done with @ rather than * since V2.80.
eg matrix = matrix * Matrix.Rotation(1.5707963267948966, 4, 'Z')
should be matrix = matrix @ Matrix.Rotation(1.5707963267948966, 4, 'Z')
or (arguably) better matrix @= Matrix.Rotation(1.5707963267948966, 4, 'Z')
or even better from math import pi; matrix @= Matrix.Rotation(pi/2, 4, 'Z')
See https://blender.stackexchange.com/questions/129473/typeerror-element-wise-multiplication-not-supported-between-matrix-and-vect
Also you can get the inverted matrix with matrix.inverted()
rather than the in-place matrix.invert()
2 Likes
Ah thanks. This is the print out before and after the multiplication.
parent_matrix = pose_bone.parent.matrix
print(parent_matrix)
<Matrix 4x4 (1.0000, 0.0000, 0.0000, 0.0000)
(0.0000, 0.0000, -1.0000, 0.0000)
(0.0000, 1.0000, 0.0000, -1.0000)
(0.0000, 0.0000, 0.0000, 1.0000)>
matrix = parent_matrix * Matrix.Rotation(1.5707963267948966, 4, ‘Z’)
print(matrix)
<Matrix 4x4 (0.0000, -0.0000, 0.0000, 0.0000)
(0.0000, 0.0000, -0.0000, 0.0000)
(0.0000, 0.0000, 0.0000, -0.0000)
(0.0000, 0.0000, 0.0000, 1.0000)>
@Gorgious I’ll give that a go thankyou.
Replacing ‘*’ with ‘@’ was all that was needed! Thankyou both for you help!
To elaborate * is still a valid operator between matrices but it will multiply the matrices element wise, meaning Matrix 1 row 1 column 1 will be multiplied with Matrix 2 row 1 column 1, etc…
90 degree rotation matrices have their ones and zeroes swapped in regard to say an identity matrix so I’m not surprised it lead to an un-invertable matrix.
Further reading https://peps.python.org/pep-0465/#background-what-s-wrong-with-the-status-quo
Cheers
2 Likes