How do a mesh object's matrix attributes relate to the global position of its vertices:
And what is each of these used for (practical examples, if possible, would be helpful)?
How do a mesh object's matrix attributes relate to the global position of its vertices:
And what is each of these used for (practical examples, if possible, would be helpful)?
Practical examples
Object.matrix_basis
- If you want to modify the loc/scale/rotation directly, as a matrix - without having to worry about what kind of rotation is used - (Euler, Axis-Angle, Quaternion).
Object.matrix_local
- Exporters where you want to write out parent relative transformation.
Object.matrix_parent_inverse
- Any tools that handle the transformation relationship between parents and children. (Not used often)
Object.matrix_world
- Any time you want to know the final transformation of an object after animation, drivers, constraints and parenting are applied. You would want to use this for example - if you are writing to a format like OBJ which doesn't store object transformations.
In python-ish syntax this is what I have deduced:
obj.matrix_basis == ( Matrix.Translation(obj.location)
*obj.rotation_quaternion.to_matrix().to_4x4()
* scale_matrix(obj.scale) )
# replace rotation_quaternion with rotation_euler if you are using Euler mode
obj.matrix_local == obj.matrix_parent_inverse * obj.matrix_basis
if obj.parent == None:
obj.matrix_world == obj.matrix_local
else:
obj.matrix_world == obj.parent.matrix_word * obj.matrix_local
# if vertex_local is the location of a mesh vertex
vertex_world = obj.matrix_world * vertex_local
# assuming no modifiers are doing interesting stuff
The strangest element of this chain is matrix_parent_inverse. Usually it is an identity matrix, but if you parent something using the Ctrl-p menu, this matrix_parent_inverse gets set so that the location and rotation properties appear to still function in their previous reference frame instead of in the reference frame of the new parent.
I haven't dug around to figure out what operators I can use to manipulate (or preferrably reset-to-identity) the matrix_parent_inverse without resorting to python.
Blender is quite tricky about bases changes because it uses unusual frames (the frames Si in the notation below) attached to the objects. Traditionally, mathematicians or physicists use only intrinsec frames (the frames Ri in the notaion below). I took quite some time to understand the behaviour and took some notes for myself. Sorry this is in French, but I hope it can help.
A comment asked for a summary: I give precise mathematical definitions of the matrices with the introduction of the adequate frames to give these definitions. I also analyse a precise definition of Matrix.decompose() in mathematical terms. Finally, we cand define only two matrices on the four matrices because there are two relations. If one matrix is changed, how do the three other change ? I report my experiments and my understanding on this point .
Again, I apolgize for the language, but I was too lazy to translate my personal notes, and I thought it was better than nothing, since I have not found this information on the Internet.
The part you'll be interested starts with : "Donnons nous n Objets ... "
Bon courage !
Chaque objet est muni de 4 matrices: matrix_basis, matrix_local,matrix_parent_inverse, et matrix_world. Ces matrices servent a placer l'objet par rapport au parent et par rapport au monde exterieur. Bien sur, il va y avoir des relations entre toutes ces matrices puisque si on sait positionner un objet par rapport a son parent, et si on sait positionner le parent dans le monde exterieur, on sait placer l'objet par rapport au monde.
Les matrices dont on parle sont des matrices 4x4 associees a des changements entre de reperes. Techniquement, ces matrices 4x4 sont construites de la facon suivante. Un deplacement est une transformation affine, qui se prolonge en une transformation projective et la matrice du deplacement est la matrice 4x4 de la transformation projective.
Comme la transformation est affine et que ce n'est pas une transformation projective generale, la matrice 4x4 ne contient que 12 coefficients significatifs ( le groupe des transfo affine est de dim 12) : La sous-matrice 1x4 du bas est toujours [0,0,0,0,1]. Le groupe des transfo affines est produit semi-direct des transfo vectorielle et des translations, ce qui signifie concretement que le deplacement se decompose de facon unique sous la forme d'une transformation conservant l'origine suivi d'une translation. La transformation vectorielle se lit dans la matrice 4x4 utilisee par Blender: c'est la sous-matrice 3x3 en haut a gauche. Le vecteur de translation est la sous-matrice 3x1 en haut a droite. On peut donc acceder facilement a ces informations.
La commande Matrix.decompose()) permet non seulement d'obtenir le vecteur de translation, mais aussi des informations sur la partie vectorielle de la transformation affine. Donnons nous une transformation affine de matrice P de taille 4x4, de partie vectorielle M de taille 3x3 et de translation de vecteur t de taille 3x1 . La decomposition polaire du groupe GLn permet de representer M sous la forme M=OS, avec O=matrice orthogonale et S=matrice symetrique definie positive. Soit v le vecteur des valeurs propres de S (defini a permutation des termes pres). Alors P.decompose()=(t,O,v)
Donnons nous n Objets O1,...On de sorte que O1 est le pere de O2, qui est le pere de O3... Chaque objet Oi est initialement place' dans un repere Ri. Ici un repere affine est la donnee de 4 points non coplanaires de l'espace. Puis on peut bouger l'objet dans son repere local par un deplacement di et representer ce deplacement par une matrice Mi. Ce deplacement definit un nouveau repere Si=di(R_i). Je note M(R1,R2) la 4x4 matrice de la transformation f telle que f(R1)=R2. Ou si on prefere, un point de coordonnees co1 and co2 dans R1 et R2, alors f(co2,1)=(co1,1). Avec ses conventions O1.matrix_world=O1.matrix_local=01.matrix_basis=M1 O1.parent_inverse=1 et pour i>1 Oi.matrix_basis=Mi=M(Ri,Si) Oi.matrix_local=M(S(i-1),Si) Oi.matrix_parent_inverse=M(S(i-1),Ri) Oi.matrix_world=O(i-1).matrix_world*Oi.matrix_local
En termes intuitifs, matrix_basis est la matrice decrivant le placement de l'objet i dans son repere local, matrix_local decrit le changement entre le repere Si attache' a l'objet i et le repere attache' a l'objet i-1, matrix_parent_inverse sert a decrire comment on a attache' l'objet i a son parent i-1 et matrix_world agrege les matrices precedentes pour avoir des coordonnees globales.
On voit que sur les 4 matrices de Oi, seules deux sont necessaires, les 2 autres se determinent par calcul puisqu'on a deux relations, la relation de la derniere ligne et matrix_basis*matrix_parent_inverse=matrix_local
Quand on change une matrice, les donnees ne sont plus coherentes
entre les differents changement de repere au sens ou elles
ne satisfont plus les relations precedentes. Blender doit
recalculer pour
reproduire des matrices coherents et il le fait a l'occasion de
l'appel de fonction scene.update. Le probleme est qu'il y a plusieurs facons de
respecter cette coherence.
Apres essai-erreur, j'ai remarque' que Blender faisait les calculs de
la facon suivante:
- si on change matrix_basis ou matrix_world, cela revient a bouger
l'objet dans son systeme de coordonnees locales : Blender prend en
compte la matrice qu'on a modifie', laisse inchangee la matrice
matrix_parent_inverse, puis recalcule les deux autres matrices en
fonction de ces deux la.
- si on change matrix_parent_inverse : cela revient a bouger la facon
dont l'objet i est attache' a l'objet i-1. Blender prend en compte la
nouvelle matrice parent_inverse, conserve inchangee la matrice
matrix_basis, puis calcule les matrices restantes a calculer.
- on ne peut pas changer seulement matrix_local, ca donne des
reslutats incoherents au sens ou apres update de la scene, les
matrices ne satisfont pas les relations qu'elles devraient. Il semble
qu'il y ait un bug ici.