You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Note that there is no distinct concept of a "geometry" here. Instead, we look for attributes (collections of named accessors) that happen to contain the same accessors, and cache them...
... so that if other primitives use the same attributes, they refer to the same BufferGeometry and we avoid a duplicate upload. If any attributes differ, the whole BufferGeometry must be duplicated (see #17089).
If (like the example above) there are multiple primitives in the mesh, we get this in three.js...
... and if there were only one primitive in the mesh, we'd drop the THREE.Group and try to "merge" the mesh and primitive concepts, which inherently could lose names or .userData.
I noticed today that:
glTF mesh primitives may have .extras/userData
GLTFLoader assigns a primitive's .extras/userData to a BufferGeometry
If the geometry is cached, a primitive may get geometry with the wrong .extras/userData
The userData caching issue isn't urgent; I'm not aware that it's affecting users.
But relatedly (reported in #29753) if a glTF mesh has only one primitive, then GLTFLoader will collapse the primitive and the mesh into one THREE.Mesh object, and the mesh name appears nowhere in the resulting scene.
We could fix the .userData issue just by including .extras/userData in the cache key. May duplicate geometry and raise VRAM cost in rare cases.
To fix that and the missing mesh name issue, we would probably want to avoid 'flattening' the scene graph: when a mesh has only one primitive, still return a "Group>Mesh", not just a "Mesh", corresponding to the glTF "Mesh>Prim" pair. Then assign the primitive's .extras/userData to the Mesh, not the BufferGeometry. Arguably makes more sense than assigning .extras/userData to the Geometry, because a glTF primitive has a material and is uniquely mappable to a three.js Mesh, whereas we want to aggressively cache geometries for performance.
Observe that geometry in the resulting scene is reused for both meshes, so the second .userData goes missing, and that the mesh names occur nowhere in the scene graph (only the parent node's name is found).
The mesh's name is lost because we've flattened the scene graph slightly: if a mesh has more than one primitive, the mesh corresponds to a Group, if the mesh has only one primitive, we skip the Group. I think this might be too complex.
Code
The model used to test this issue was generated with the glTF Transform script below.
donmccurdy
changed the title
GLTFLoader: Geometry cache mixes .userData
GLTFLoader: Conflicting mesh/primitive/geometry/userData mappings
Oct 30, 2024
donmccurdy
changed the title
GLTFLoader: Conflicting mesh/primitive/geometry/userData mappings
GLTFLoader: Conflicting mesh/primitive/geometry mappings
Oct 30, 2024
tl;dr — I think we should perhaps stop trying to automatically flatten the scene graph in GLTFLoader (reversing some changes from #11944) and instead return a consistent mapping...
Description
In glTF's data model, we have:
Note that there is no distinct concept of a "geometry" here. Instead, we look for attributes (collections of named accessors) that happen to contain the same accessors, and cache them...
three.js/examples/jsm/loaders/GLTFLoader.js
Lines 2450 to 2456 in 09c38ab
... so that if other primitives use the same attributes, they refer to the same BufferGeometry and we avoid a duplicate upload. If any attributes differ, the whole BufferGeometry must be duplicated (see #17089).
If (like the example above) there are multiple primitives in the mesh, we get this in three.js...
... and if there were only one primitive in the mesh, we'd drop the THREE.Group and try to "merge" the mesh and primitive concepts, which inherently could lose names or .userData.
I noticed today that:
The userData caching issue isn't urgent; I'm not aware that it's affecting users.
But relatedly (reported in #29753) if a glTF mesh has only one primitive, then GLTFLoader will collapse the primitive and the mesh into one THREE.Mesh object, and the mesh name appears nowhere in the resulting scene.
We could fix the .userData issue just by including .extras/userData in the cache key. May duplicate geometry and raise VRAM cost in rare cases.
To fix that and the missing mesh name issue, we would probably want to avoid 'flattening' the scene graph: when a mesh has only one primitive, still return a "Group>Mesh", not just a "Mesh", corresponding to the glTF "Mesh>Prim" pair. Then assign the primitive's .extras/userData to the Mesh, not the BufferGeometry. Arguably makes more sense than assigning .extras/userData to the Geometry, because a glTF primitive has a material and is uniquely mappable to a three.js Mesh, whereas we want to aggressively cache geometries for performance.
Reproduction steps
prim_extras_test.gltf
(attached)prim_extras_test.zip
The mesh's name is lost because we've flattened the scene graph slightly: if a mesh has more than one primitive, the mesh corresponds to a Group, if the mesh has only one primitive, we skip the Group. I think this might be too complex.
Code
The model used to test this issue was generated with the glTF Transform script below.
script.js
Live example
Open the model attached above in https://threejs.org/editor/.
Screenshots
No response
Version
r168
Device
Desktop, Mobile, Headset
Browser
Chrome, Firefox, Safari, Edge
OS
Windows, MacOS, Linux, ChromeOS, Android, iOS
The text was updated successfully, but these errors were encountered: