A 4x4 homogeneous matrix can represent any affine transformation. That is, any combination of:
- Translation by any offset
- Rotation around any axis by any angle
- Scale along multiple arbitrary axes by any scale factor
- Shearing in any plane by any factor
Including any arbitrary composition of the above, in any order - like rotating then scaling then rotating and scaling again.
But there are good reasons why we don't want to use a 4x4 matrix as the "source of truth" for the transformations of objects in our game scene.
Repeated transformations of a matrix can allow rounding errors to creep in and distort our objects, or even flatten them to a plane/line/point!
Decomposing a matrix, like if we wanted to isolate and read or change just the rotation component, is somewhat expensive.
It's also ambiguous: we can't tell the difference between an object that's been rotated 180 degrees, versus one that's been scaled by a factor of -1 on two axes: the net transformed result is the same. So we lose some information when we compose transformations into a matrix.
For this reason, game engines often store the "source of truth" for an object's transformation as separate components, and generate the corresponding matrix on demand from that source. Frequently these source components will be:
- Translation vector
- Rotation quaternion or Euler angle triplet
- Scale factors along the object's 3 local coordinate axes
(Note that this is also just 9-10 floats, a little lighter than the full 16 needed for a 4x4 matrix)
When we need to update the matrix for rendering, we can build it by applying these three components in order from right to left:
$$M = T \times R \times S$$
Applying this matrix to a vector \$vec v\$ is the same as first multiplying that vector's x, y, and z components by the axis-aligned scale factors, then rotating the result around the origin, then adding the translation vector to that rotated result.
$$M \times \vec v = T \times R \times S \times \vec v$$
(See this answer that goes into more depth about constructing and using matrices like this)
This covers the set of transformations we most frequently use in 3D games, but it's not as expressive as a 4x4 matrix. We can't use a single set of the components above to represent shearing transformations, or scaling along a diagonal axis.
That means we cannot make every matrix \$ M\$ in this way.
In environments like this, the object's transformation matrix will either be read-only (like in Unity), or if you're allowed to "set" it, what you're really doing is requesting a transformation as close as possible to the value you provide. The framework will then try to find some combination of translation, rotation, and axis-aligned scale that comes closest to matching the matrix you provided, maybe using an algorithm like this one.
That latter seems to be what Qt3D is doing, according to the answer you linked. So when you set a matrix, what you're really doing is asking the framework to calculate the best matching \$T\$ \$R\$ and \$S\$, and then assign the matrix \$M = T \times R \times S\$, even if that \$M\$ doesn't exactly match the matrix you provided.
In particular, if you have a parent object with a non-uniform scale applied, and a child object that is rotated diagonally to that parent, then the net effect of that transformation is a shear, or a scale along a diagonal axis of the child.
As we saw above, we can't represent a diagonal scale/shear in TRS form. So if you make an inverse matrix that cancels out the diagonal scale, and try to assign it to the child, the framework has no valid choice of \$S\$ that exactly matches the diagonal scale you're trying to apply. It has to compromise and pick the closest axis-aligned scale instead.
The best fix for this is to avoid applying non-uniform scales to parent objects. Consider making an invisible parent with only uniform scale, then give it two children: one with non-uniform scale representing the original parent's visual, and the second representing the original child. By keeping non-uniform scale out of the parent chain, you ensure you don't get these shear transforms that we cannot correct by applying the inverse to child objects.