Example above will load a large texture (5.5 MB) from the Babylonjs texture library after a second. If you move the camera during the first second you can see when it hits the big hitch and freezes up for a period. In Chrome at least you may also see it complain in the console about a violation on the load handler.
This pause does not appear to be an issue with the actual network speed, since in Chrome we can throttle ourselves and the hitch is about the same duration each time. It instead seems to be CPU based and related to resolving the asset into the final scene upon completion of the download, which happens asynchronously in the background.
To the point: is it possible to mitigate this? Is there an alternate way to load an asset (a texture in my case) such that the entire process to get it into the scene is done asynchronously and doesn’t cause one large frame drop? In our own app we are trying to load lower quality textures first to get users into the app quicker, and then drop in the higher fidelity textures at runtime whenever they happen to finish downloading.
Hi!
You can load the texture async but it will not help. The hitch is caused by a WebGL call (to my best knowledge) which can’t be avoided. You can create your textures on startup however.
You can see here that you can move the camera without stuttering while the texture is downloading but the movement skips when the texture is created in the WebGL context.
I see. In the same playground, if we load in the 4.7 MB “./textures/specmap.png” instead, it seems to still be visible though a lot less problematic. Would the file format + file size be the deciding factors in how well WebGL handles the creation of the texture?
JPG and PNG textures are transferred to the GPU in an uncompressed data format. Maybe the JPG decompression takes more time so the PNG seems to be faster. You might want to consider a compressed texture format which results in smaller data size (fewer data to upload to the GPU so faster) and are optimized for faster sampling on the GPU.
oh shit, on first load i got a major stutter like the op using the non-power of 2 image.
the 12000 ms vs 220 ms is me just running it again, completely random.
the resized version runs at 35ms, but its a smaller file now also.
my changes
the original was 3840x1920 and I rescaled it using that online photo editor to 2048x2048 (the copy i uploaded to github) . This reduced the load time from 220 to 30
I couldn’t go below 100 ms with this example. My Omniverse has failed lol !
i9 5Ghz/RTX 3080Ti, wtf… What are your specs? You don’t need to specify the PSU I know you don’t even have one
png vs jpg is unclear, but likely not as significant as other factors.
Comparing the 5mb 2048x4096 rectangle vs 2048x2048 square, the square loaded 18ms faster with the same data size at 68ms vs the rectangle 86ms. This supports the articles claim that squares are faster.
data size reduction to speed is logarithmic
16mb reduction to 5mb yields reduction from 135ms to 85ms. roughly 2:1 for this case.
5mb reduction to 1mb yields reduction from 65ms to 35ms. roughly 2.5:1 for this case.
It seems to be very HW dependent because on my PC:
8192px 750ms
8191px 800ms
so I can say there is no difference for me. I did one more test with the JPG and:
but also, those textures are huge. we’re definitely limited by chrome. chrome has to check the other frames first so it can be sure we dont miss any ads. also some jitter helps prevent leet hacks, so its not all terrible
//const res = await fetch("https://playgrounds.babylonjs.xyz/textures/aerial_rocks_02_diff_8192x8192.jpg") // ~750 ms //700-1700
//const res = await fetch("https://playgrounds.babylonjs.xyz/textures/aerial_rocks_02_diff_8192x8192.png") // ~800 ms //1200
//const res = await fetch("https://playgrounds.babylonjs.xyz/textures/aerial_rocks_02_diff_8191x8191.jpg") // ~ 800 ms //580
const res = await fetch("https://playgrounds.babylonjs.xyz/textures/aerial_rocks_02_diff_8191x8191.png") // ~1500 ms //1200
for those huge textures, it’d be worth putting in a worker. can’t really do that so easily in a playground. doable though. we could actually just put an iframe in the playground and wrap all the js code into a base64 and put it as the src, then use esm imports and module workers.
this slide from the latest khronos youtube video shows how to do it in webgpu
the main power being that createImageBitMap is available in workers
EDIT: Actually I can’t make good jokes in English and maybe sometimes my reactions doesn’t reflect what I really want to say but I definitely like these little jokes LOL