Struggling with Invalid Matrix
See original GitHub issueI’ve been struggling with matrices lately, and I’m wondering whether Matrix4x4.Decompose is too strict or the matrix is truly poorly formed.
I’m using the SceneBuilder API to put together a node hierarchy. For each node, I set the local matrix like so:
var nb = nodeBuilder.CreateNode(bone.Name);
nb.UseTranslation().Value = bone.Position;
nb.UseRotation().Value = bone.Rotation;
nb.UseScale().Value = bone.Scale;
Then, I create a mesh, and calculate the inverse bind matrices:
var nb = nodeBuilders[bb.BoneIndex];
var wm = nb.WorldMatrix;
Matrix4x4.Invert(wm, out Matrix4x4 wmi);
wmi.M44 = 1; // force to be one
return (nb, wmi);
Note: Somehow M44 becomes 0.999999, which is probably due to a precision error caused during the Invert method, and the gltf validator doesn’t like this so I forced it to a 1.
Now when I save the gltf file, I get a complaint that a matrix is invalid. I commented out the part that throws the exception just to force the file to save and I can inspect it on my own.
I believe this is due to the Matrix4x4.Decompose function returning false. I think it returns false because the determinant of the rotation part of the matrix is <0.985 as opposed to 1.0 and that’s enough to fail the “DecomposeEpsilon” threshold. When I use the gltf validator provided by Khronos, it says the file is valid.
I guess the question is whether these matrices are good enough and the Decompose method is too strict. I also wonder where the imprecison comes from. The local matrices are created from proper position, rotation, and scale data. Maybe if the hierarchy is deep enough, then computing the world matrix loses precision after so many local matrices are multiplied together.
I just wanted to get your thoughts on this, and what we can do about this. I have attached an example gltf. grnGltf.zip
Thanks!
I also posted a similar issue in the dotnet repo where Decompose returns false in an even simpler example. I was hoping someone could explain how precision was lost, and what to do about it. Initially I thought it was a bug, but now I think either the threshold is too strict, or there are precision problems. https://github.com/dotnet/runtime/issues/34874
Issue Analytics
- State:
- Created 3 years ago
- Comments:24 (24 by maintainers)
Top GitHub Comments
I understand the difference between SxR and RxS is that in the latter, the uneven scaling is applied to the axes on an already unaligned matrix (because it was previously rotated) and that produces a skewed matrix. It is not possible to do with a single local matrix. But it is possible to do with a rotated parent node, and an unevenly scaled child node.
Yes, that’s why my original code for matrix normalization used columns instead of rows. But I’ve made some further checks, and for some reason, it only works well if applied to rows.
It doesn’t hurt either, and I believe it can be useful to improve precission with long hierarchy chains, so I’ll probably leave it.
That class looks very much like Transforms.AffineTransform, maybe I could add that functionality to it.
Yes, I think you’re right. I just wish I could find something that explains this mathematically in the context of TRS matrices. I also realize now that the columns/rows of orthogonal matrices are not just orthogonal, but also orthonormal so I’ve been using that term wrong, and scaled matrices are not orthogonal.
Anyway, I think this is the correct solution. I don’t think the double matrix4x4 made much of a difference in the end and can probably be removed.
By the way, here’s my implementation of skipping matrices, and using only SRT parts to create a world matrix. The code is really ugly since I put it together really fast for my testing. https://gist.github.com/ptasev/bce22ca61d9da83a702c2011229b76ab