Open ConanNobita opened 1 year ago
Maybe others can chime in here from the perspective of someone who has more experience with implementing actual renderers, or know a wider range of application cases and/or the associated file formats (or more generally: ways of storing and structuring rendering data).
But I don't see too much of an overhead here:
A mesh
can be attached to an arbitrary number of node
objects. So even if a mesh is attached to 10 nodes, it "exists" only once in memory (but is rendered 10 times, basically just with different model matrices)
A mesh
contains multiple mesh.primitive
objects. The mesh primitive itself refers to attributes and indices (via accessor
objects). So the mesh.primitive
does not "store" or "contain" or "own" the actual data. You can have mesh primitives like
{ "attributes": { "POSITION": 12, "COLOR_0": 111 }, "indices": 34 },
{ "attributes": { "POSITION": 12, "COLOR_0": 222 }, "indices": 34 },
{ "attributes": { "POSITION": 12, "COLOR_0": 333 }, "indices": 34 },
{ "attributes": { "POSITION": 12, "COLOR_0": 444 }, "indices": 34 },
They will use the same positions and indices, but each one uses different vertex colors.
And finally, the mesh.primitive
is associated with the material
. So you can have mesh primitives like
{ "attributes": { "POSITION": 12 }, "indices": 23, "material": 111 },
{ "attributes": { "POSITION": 12 }, "indices": 23, "material": 222 },
{ "attributes": { "POSITION": 12 }, "indices": 23, "material": 333 },
{ "attributes": { "POSITION": 12 }, "indices": 23, "material": 444 },
They will all use the same positions and indices, but different materials.
Or to put it that way:
The mesh.primitive
is not the "object that contains the data". It is a rather lightweight object - basically a description about how to render certain data. Referring to the example:
// Render the SAME geometry data (!) several times....
{ "attributes": { "POSITION": 12 }, "material": 111 }, // ... once with material 111
{ "attributes": { "POSITION": 12 }, "material": 222 }, // ... once with material 222
{ "attributes": { "POSITION": 12 }, "material": 333 }, // ... once with material 333
{ "attributes": { "POSITION": 12 }, "material": 444 }, // ... once with material 444
I do agree that the concept of "reusing" geometry with different materials is a very common idea across software, and it's a mild inconvenience that this can't be neatly expressed in glTF. For three.js, in order to avoid uploading geometry to the GPU twice, we compute a hash key for each primitive (excluding the material), and if we encounter that hash key again we reuse the previous geometry.
This has been OK. Ideally I wish that we (three.js) had a storage API for vertex data that was more flexible, closer to glTF's buffer views, and then this would be purely a semantic issue rather than a performance issue. That is likely something we'll do in the future, but still the idea of reusing geometry with different materials is a persistent concept for artists.
tl;dr — I'd add a soft +1 for this proposal in a glTF 3.0 future (if that is someday necessary), but I don't think it's necessary or worthwhile to make changes within the glTF 2.0 lifecycle or through glTF 2.0 extensions.
Some libraries used to parse glTF formats will convert glTF data into other resources, such as UnityGLTF and Assimp. UnityGLTF will generate multiple Unity Mesh resources based on the number of Meshes in the glTF, rather than reusing them. This approach may be due to the format limitations of glTF. If I write code to parse glTF, I will create a cache table and use some algorithms to determine whether Mesh has been generated.
tl;dr — I'd add a soft +1 for this proposal in a glTF 3.0 future (if that is someday necessary), but I don't think it's necessary or worthwhile to make changes within the glTF 2.0 lifecycle or through glTF 2.0 extensions.
I agree with this approach. Thanks for your reply
I think saving the material index in MeshPrimitive may not be a good design We would like to use the functionality of glTF. We need to frequently handle oversized scenes and reuse meshes as much as possible, but MeshPrimitive is associated with materials, which can lead to the generation of more mesh objects, even if their vertices and indexes are consistent. Why not add an array to save the index of the material in node? The array should not use more memory than MeshPrimitive.