# The asymmetric matrix inversion issue

Hello;

some time ago there was a question about inverting transformations in hierarchies which led to an interesting finding in matrix transformations. I decided to make the discussion a chapter in my Python course. As the idea originated here, it's only fair to make this chapter public and open it for the readers here, so you can find it under

https://www.patreon.com/posts/python-spoonfed-43067386

(This is not a question as the topic cannot be solved, except for not using Object Scale with different values per axis...)

Hi,

thanks for sharing and this is certainly an issue. However, the statement in the blog that "Cinema does not support shearing matrices" is not correct. At least not as an absolute. Cinema only enforces an ortho-normal basis on the transforms of its geometry. But you can shear stuff with `c4d.Matrix`/transforms as much as you want.

Cheers,
zipit

``````"""Demonstration that Cinema does not enforce an ortho-normal basis on its
transforms (matrices) by default, only when they are applied to a BaseObject.
"""

import c4d

def main():
"""Shears a point object with a shear matrix.
"""
if not isinstance(op, c4d.PolygonObject):
pass

points = op.GetAllPoints()
# This is a transform with a non orthogonal basis/frame.
shear = c4d.Matrix(v2=~c4d.Vector(1, 1, 0))
print (shear.v1)
print (shear.v2)
print (shear.v3)
# Which works just fine.
points = [p * shear for p in points]

op.SetAllPoints(points)

# However, as soon as we apply it to an object, Cinema will silently
# correct it.

op.SetMg(shear)
mg = op.GetMg()
print (mg.v1)
print (mg.v2)
print (mg.v3)

if __name__=='__main__':
main()
``````

Well, yes, technically you are correct: you can modify a matrix into a shear matrix since you can modify the "rotation vectors" directly, but I do not think that substantiates the word support or even is the intent of Maxon, as:

• There are no factory functions/constructors for shear matrices (as exist for all other transformations, like MatrixMove, MatrixScale, MatrixRotX/Y/Z)
• There are no functions to determine the shear component from an arbitrary matrix (as exist for many other transformations)
• The orthogonality is transparently restored on object assignment (as you said)
• As the example shows, even the internal invert operator cannot create the mathematically correct inverse matrix in the demonstrated case
• The multiplication of transformational components is out of sequence when it comes to frozen/relative matrices (I didn't make that chapter public, but it's mentioned in Maxon's own documentation on matrices)

I suppose an orthodox implementation of linear algebra would be too complex for the end user and more memory/calculation intensive (Maxon doesn't even make a difference between vectors and points, which then leads to the distinction between Mul and MulV), but it creates issues like this one

I may modify the text for a more thorough explanation though, I'm making a note...

Hi,

sure, shears are somewhat the unloved stepchild of transforms in Cinema. But I think just like for the handedness/orientation of transforms, it is important to point out that this only does kick in once applied to an object, because otherwise people will assume that Cinema is handling that for them and wonder what the heck is going wrong in their code.

One could probably argue that this is a common approach, as you usually want to enforce an common orientation for your coordinates and most often also want your geometry to be defined in a sane way in relation to an orthonormal basis, but with this line of thinking you IMHO sooner or later venture into territories, where you consider "and here comes the tricky part" to be a sufficient explanation for even the most cryptic things.

Cheers,
zipit

@zipit said in The asymmetric matrix inversion issue:

Hi,

sure, shears are somewhat the unloved stepchild of transforms in Cinema. But I think just like for the handedness/orientation of transforms, it is important to point out that this only does kick in once applied to an object, because otherwise people will assume that Cinema is handling that for them and wonder what the heck is going wrong in their code.

I guess it depends on the point you want to make. I added this chapter to show that Cinema is not working with "pure" linear algebra, which can lead to possible strange transformations. The purpose is more or less that script programmers are aware that these things might happen, and that they should avoid certain things (like matrix-based asymmetric scaling) to prevent issues down the line.

Asymmetric scaling in the coordinates tab is dangerous anyway. I consider it a best practice to have the scale coordinates at 1-1-1 all the time unless you have a very good reason to transform local space.

I'm not doing the deeper math in the course anyway. For basic scripting, it suffices to use the provided matrix factories. If you want more, you'd have to take a complete linear algebra course with all the bells and whistles. (And you couldn't even completely apply it to C4D functions because C4D has some extra gatekeepers built in, like the auto-orthogonalization in SetMl() and SetMg().)

It's a fairly esoteric theme; I wasn't even aware of these issues before the topic was raised here on the forum. I just never encountered the situation - and I've been doing scripting/plugin programming since R8.

One could probably argue that this is a common approach, as you usually want to enforce an common orientation for your coordinates and most often also want your geometry to be defined in a sane way in relation to an orthonormal basis, but with this line of thinking you IMHO sooner or later venture into territories, where you consider "and here comes the tricky part" to be a sufficient explanation for even the most cryptic things.

This has, in fact, been a point I thought long and hard about. Do I start with the theoretical details, present the full math and programming theory, and then teach perfect mastery of software engineering? Or do I follow a hands-on approach which leads to working scripts early on, but leaves the "tricky parts" for later (or never...)? I decided in favor of the second method, which of course requires some extra though when it comes to the cryptic things (or it drops the cryptic things altogether until a participant explicitly runs into the issue and asks).

I suppose if we get more philosophical, we could question the way Cinema 4D handles matrices altogether. The root cause for the described issue is that C4D does not support explicitly avoids the shear transformation in its matrices to keep the coordinate system orthogonal as far as possible. At the same time it permits asymmetric scaling, with the known results.

We can imagine a 3D program that doesn't use matrix scaling or shearing at all - in which case all matrices would be invertible, and the inversion would always lead to a pure trans/rot matrix again, circumventing the issue (correct me if I'm wrong...). But maybe that is a rather severe restriction that leads to "missing feature" syndrome.

Or we can just allow a common scaling factor for all axes instead of separate x/y/z values. That makes it possible to scale objects or animations while still not encountering the shearing issue. (Scaling down to 0 would lead to non-invertible matrices, of course.) On the other hand, this is a property that the user can adhere to themselves by a little discipline.

Or we can allow shearing, implement the full range of linear algebra transformations, and thereby "complete" the feature set. (While we're at it, we can also encode the handed-ness of the coordinate system - having left- and right-handed coordinates would help a lot in rigging and animation.) Then again, this might confuse the user; while it's mathematically perfect and gets rid of all necessary exceptions, it introduces yet another level of complexity. Also, a deep understanding of that solution would force the user to study the math in much greater detail.

All solutions have their ups and downs. It's hypothetical anyway, as C4D will certainly not deviate from its most basic foundations

Hi,

I guess it depends on the point you want to make...

I would mostly agree, but my point point was more the other way around. Not that shearing is a thing you commonly want to do, but the fact the you should be aware that `c4d.Matrix` will not enforce an orthogonal basis. Because if you thought it does, you could for example think that

``````my_frame = c4d.Matrix(v3=my_normal)
``````

would be a sufficient way to construct an orthogonal frame where `my_normal` is k and then carry out some transforms with it and wonder what the heck is going wrong.

This has, in fact, been a point I thought long and hard about...

What I meant with that passage was the story which has been attributed to many famous programmers who left a complicated piece of code only commented with "and here comes the tricky part". Usually told as a testament to both their technical genius and their communicative shortcomings. The often (at least silently) admired notion is that "everything is self explanatory for a smart person". Which of course is neither true nor very "cool". I feel you are drifting a bit into that direction.

About the linear algebra stuff. In my opinion there is no wrong or right there, you can do a good job with a very coarse and with a very fine model. Although I think often the geometrical meaning of linear algebra has been neglected in teachings about it. Especially Cinema's "matrices" (which in my book do not really qualify as matrices) can be very well explained as linear maps which will automatically will make all four principal transforms intuitively clear. Everything that is left then is to explain that matrices are just another way to write a linear map, i.e. a linear combination of vectors representing a coordinate system.

Cheers,
zipit