vpenades / SharpGLTF

glTF reader and writer for .NET Standard
MIT License
476 stars 75 forks source link

Support Double Precision in Transformation Matrix #176

Closed dagrooms52 closed 4 months ago

dagrooms52 commented 1 year ago

I'm having issues with the transformation matrix on a glTF model. The model is in ECEF coordinates, so I've extracted the centroid to a translation vector of doubles that should be stored on a Node's translation or matrix properties. I found that I was only able to write floats to the glTF model using SharpGLTF's built-in functions such as Node.WithLocalTranslation or Node.LocalMatrix. This led me to modify the glTF JSON after writing it out, placing the translation values in the matrix property and rewriting the glTF file.

Is there a reason doubles are not supported in the library? glTF spec seems to support them, and it is crucial to store double precision for accuracy of ECEF coordinate data.

I get the following error when attempting to call ModelRoot.Load on the file after writing doubles in the transformation matrix:

Node[0] Matrix: Invalid MatrixModel generated by <SharpGLTF 1.0.0-alpha0027> seems to be malformed.

The transformation matrix section of the glTF JSON (includes Y to Z up rotation and translation to ECEF):

"nodes": [
    {
      "matrix": [
        1,        0,        0,         1335838.536088313,
        0,        0,        -1,        -4659713.478714659,
        0,        1,        0,         4131346.164399078,
        0,        0,        0,         1
      ],
      "mesh": 0
    }
  ],

please complete the following information:

vpenades commented 1 year ago

Is there a reason doubles are not supported in the library? glTF spec seems to support them, and it is crucial to store double precision for accuracy of ECEF coordinate data.

Yes, simplicty.

95% of users are fine with floats, and it's easier for me to develop and maintain. If I would have chosen doubles just to please the 5% of users that require it, it would have been a burden for the rest 95% of users.

Anyway, supporting doubles along the whole API would take literally months of work, so it's out of the question to support it.

Also, I think glTF discourages double precission to some degree. the rule of thumb is that the scene origin should be set at the origin (0,0,0) and the nodes to be set relative to the origin. So you can "place" the asset in multiple locations using external coordinates. An example of this is that animated transforms are explicitly stored using floats only. It would be awkward that animated transforms to have less precision than unanimated transforms.

I am not an expert, but I think what you're looking for is some Cesium extensions like 3d-tiles which support extra metadata describing the geographic location of an asset. I think what others do is to store the geographic location as an Model's Extra property, or via extensions

Maybe @bertt can give more insight about this issue.

I get the following error when attempting to call ModelRoot.Load on the file after writing doubles in the transformation matrix:

Node[0] Matrix: Invalid MatrixModel generated by <SharpGLTF 1.0.0-alpha0027> seems to be malformed.

The transformation matrix section of the glTF JSON (includes Y to Z up rotation and translation to ECEF):

"nodes": [
    {
      "matrix": [
        1,        0,        0,         1335838.536088313,
        0,        0,        -1,        -4659713.478714659,
        0,        1,        0,         4131346.164399078,
        0,        0,        0,         1
      ],
      "mesh": 0
    }
  ],

That's wrong, positions should go at the bottom of the columns, not at the right of the rows.

dagrooms52 commented 1 year ago

Thanks, I agree with your assessment. glTF spec discourages doubles in model vertices (I down-sampled to floats before which caused quality issues) but shouldn't have an issue storing a Vector3 of doubles in the translation property or in the transformation matrix.

I wanted to try putting translations in the glTF model first since if I add them to the Cesium 3DTiles, they propagate down to child tiles, and I have a long hierarchy of tiles. I'm calculating the offset per-tile, so naively adding offsets to tiles as I build them will compound, meaning only the first parent tile with an offset would be in the correct position and everything else will be off in space.

Since the glTF models I'm writing out with this library appear to be valid, I will probably look for another tool that can pack my resulting glTF files into a glb since that's the only remaining operation needed here.

And thanks for pointing out the positions, I had to hand-jam the translation and couldn't figure out whether to write row-major or column-major based on some external docs