Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GLTFLoader: Separate asset loading order #18097

Closed
4 of 12 tasks
TyLindberg opened this issue Dec 7, 2019 · 5 comments · Fixed by #18132
Closed
4 of 12 tasks

GLTFLoader: Separate asset loading order #18097

TyLindberg opened this issue Dec 7, 2019 · 5 comments · Fixed by #18132
Assignees

Comments

@TyLindberg
Copy link
Contributor

Description of the problem

Right now when loading a .gltf file, the GLTFLoader will load all of the images first and then the .bin files. I was wondering if there was a reason for this loading order. This can be seen in this example.

One instance I can think of where loading the .bin files earlier would be preferred is with DRACO encoded meshes. If we were to load the .bin files in tandem with the images, it would allow the DRACO meshes to start being decoded earlier in the loading process, potentially before all images are loaded. This would allow certain DRACO gltf files to load faster, with the decoding happening in parallel to image loading.

Three.js version
  • Dev
  • r111
Browser
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • Windows
  • macOS
  • Linux
  • Android
  • iOS
@donmccurdy
Copy link
Collaborator

In GLTFLoader we try to avoid doing things like "load all of the _____" , with a few exceptions, to support some lazy-loading uses. So there's nowhere in the code that explicitly loads all textures or all .bin files. I think the order you see is just a side effect of this section's order:

for ( var i = 0, il = primitives.length; i < il; i ++ ) {
var material = primitives[ i ].material === undefined
? createDefaultMaterial()
: this.getDependency( 'material', primitives[ i ].material );
pending.push( material );
}
return Promise.all( pending ).then( function ( originalMaterials ) {
return parser.loadGeometries( primitives ).then( function ( geometries ) {

I don't know if switching the order would be an unambiguous improvement, for a couple reasons:

  1. GLTFLoader will eventually support Basis Universal textures, in which case the textures will need to be transcoded as well.
  2. GLTFLoader may eventually support another buffer view compression mode, in which case there would be options for decoding compressed geometry much more quickly.

But that said, if you'd like to try switching the loading order and see what the results look like, benchmarks are always nice to have. If it's a small change that improves things today maybe we should go ahead.

@zeux
Copy link
Contributor

zeux commented Dec 8, 2019

Does the order of promise invocation strongly affect the order of delivery? I'd expect all resources to get loaded in parallel, so whichever is first to actually get downloaded would win.

edit Although I guess on further reflection without HTTP/2 the number of resources that are fetched in parallel is somewhat limited, so it may take time to get through textures to the geometry, and of course resource prioritization over the HTTP/2 stream may also result in resources that are requested first to be delivered ahead of time.

And heeeeeey "may eventually support" => "will definitely support" 😜

@donmccurdy
Copy link
Collaborator

Although I guess on further reflection without HTTP/2 the number of resources that are fetched in parallel is somewhat limited...

Yes, that's my hunch. It certainly could be an improvement to request the .bin first, but it's hard to guess how much of a difference that will make or what percentage of models will benefit.

@TyLindberg
Copy link
Contributor Author

@donmccurdy Yeah, I doubt there's a clear cut loading order that would result in optimal loading time for all assets. However, I feel like being unbiased between images and .bin files may result in better load times on average. I'll spin up a solution and start running some benchmarks on the glTF sample models. Are there any tools that are typically used for benchmarking three.js loaders?

@zeux I agree that promise invocation won't strongly affect loading order especially with HTTP/2 and above. However, in the code snippet that @donmccurdy linked above, the loader waits for all image promises to resolve before invoking the loadGeometries method, hence we see the .bin files being requested only after all images are loaded. My thought is that requests for both images and .bin files should be made in parallel, since I don't believe the geometries are dependent on the images being loaded. Ultimately it will need to be benchmarked to see what actually works best.

@donmccurdy
Copy link
Collaborator

Parallelizing that sounds good to me, yes. No need to force one or the other to happen first.

Are there any tools that are typically used for benchmarking three.js loaders?

I usually do this in dev tools (e.g. console.time), although I'm more often trying to exclude network time from the results (to measure parsing) than including it. I'd suggest:

  1. Test 2-3 models, at least one that's texture-heavy, one that's geometry-heavy, and one that's smaller.
  2. Load each model 3-5 times, with the browser's cache disabled.
  3. Record times in a Google Sheet or whatever is convenient.

If we're just parallelizing things — rather than forcing .bin files to finish loading before textures — then I'm not really worried about the change, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants