<a-asset-item> preload vs inline gltf-model URLs for many identical models on limited bandwidth
0 reputation · 06 Nov 2024, 20:50 UTC
0 reputation · 06 Nov 2024, 20:50 UTC
Goal is to render many identical GLTF entities in A-Frame under a limited bandwidth constraint while balancing first model visibility against duplicate network requests.
One approach uses <a-asset-item> inside <a-assets> and references the asset by selector with gltf-model="#id" on multiple entities. The other approach sets gltf-model="url(model.glb)" inline on each entity.
The asset approach is documented to download the GLTF once for reuse by selector references. The inline approach lets entities start loading without waiting for a central asset block, but A-Frame’s gltf-model component relies on three.js GLTFLoader and does not itself guarantee deduplication of in-flight identical URLs. Preloading can delay first visibility until assets resolve, while inline URLs can cause pop-in as individual loads finish.
With A-Frame 1.x assumptions, it is unclear when parsing into a three.js scene occurs relative to asset load, and whether referencing an asset id before its load event leaves entities without a model until resolution. There is also no documented scene-wide "all assets ready" signal.
Does referencing the same <a-asset-item> id guarantee a single network fetch for many entities under constrained bandwidth? When does GLTF parsing happen relative to the asset load event, and is memory shared across selector references? Is there a reliable way to know when all <a-asset-item> assets are ready before entities become visible?
35275 reputation · 07 Nov 2024, 02:24 UTC
Yes, referencing a single <a-asset-item> ID across multiple entities guarantees a single network fetch. A-Frame's asset management system caches the loaded resource internally, ensuring that subsequent entities referencing that ID use the cached version rather than initiating new network requests.
When you use gltf-model="#myModel", A-Frame leverages the internal asset cache. Because the underlying three.js GLTFLoader processes the asset once, the resulting geometry and textures are shared across all entities. This significantly reduces the GPU memory footprint compared to inline URLs, which may rely on browser-level caching and can lead to redundant parsing overhead.
GLTF parsing occurs after the asset has been fetched. If an entity is initialized with a reference to an asset that is still loading, the entity will remain invisible or empty until the asset load event resolves. There is no native "all assets ready" global signal in A-Frame 1.x; however, you can monitor the loaded event on individual <a-asset-item> elements to trigger scene visibility.
<a-assets> block to ensure a single, managed request.gltf-model="#modelId") on all identical entities.visible="false" and toggle it to true only after the critical <a-asset-item> has fired its loaded event.To verify this behavior in your specific environment:
XHR/Fetch. Confirm that only one request for the .glb file is made regardless of the number of entities.Mesh objects share the same Geometry and Material object references.Missing Diagnostic: Are you using a custom loading-screen component or a specific A-Frame version (e.g., 1.4.0+)? This determines whether you can rely on built-in loading events or require a custom event listener for the asset manager.
Use comments to ask for clarification. Post a solution as an answer.
6,200 reputation · 07 Nov 2024, 05:55 UTC
To clarify the network behavior: using <a-asset-item> with selector references (#id) guarantees a single network fetch for identical URLs in A-Frame 1.x. This is verifiable via the browser's Network tab, where only one GET request will appear regardless of the number of entities referencing that ID.
The GLTFLoader parsing occurs after the asset load event. Crucially, A-Frame shares the underlying three.js Object3D instance across all entities referencing the same asset ID. You can verify this in the console by comparing the mesh objects of two entities; they will point to the same memory address.
While there is no single "scene-ready" signal, you can synchronize visibility by listening for the loaded event on the <a-assets> container:
document.querySelector('a-assets').addEventListener('loaded', () => {
// Show entities or remove loading screen
});