Reputation: 7346
I currently have a big impact on the performances of my ThreeJS app when I render the very first frame. It causes the Edge and IE 11 browsers to freeze for 5 seconds with a pop-up indicating "This window does not respond", which may scare my users.
Using the Performance profiler of Chrome, it seems the problem come from several ThreeJS functions you can clearly identify in the screenshot below.
WebGLUniforms.upload
: 425ms (50.7% frame rendering time)WebGLProgram.constructor
: 327ms (38.9% frame rendering time)How can I minimize the duration of the functions call ?
Can I create the program over multiple frames? Or upload the uniforms?
Does the number of materials on my 3D models impact these functions ?
I've tried to hide all the models in the scene and show them one at a time, it seems to prevent the freeze, but each model takes 500ms to show, which is not perfect for user experience. Maybe, it's the only way to go.
Thanks for your time
EDIT : The number of materials or their nature (WebGLStandardMaterial?) seems to affect the performances
Upvotes: 3
Views: 1422
Reputation: 61
You can pre render your scene(s) during the first 1 second calling the renderer.render(camera, scene).
First set auto clear to false
renderer.autoClear = false;
Your pre render does the first painting
const preRender = (time = 1000) => {
return new Promise((resolve) => {
const startTime = performance.now();
function checkTime(currentTime) {
if (currentTime - startTime >= time) {
// pre render finished
resolve();
} else {
requestAnimationFrame(checkTime);
// so the first frames occur here!
renderer.render(scene, camera);
renderer.clear();
}
}
requestAnimationFrame(checkTime);
});
};
Then your instructions would look like this:
preRender().then(() => render());
Render is your loop, where you render your scene(s) normally.
const render = () => {
requestAnimationFrame(render);
// your custom logic
renderer.render(scene, camera);
}
During pre render time you can show a loading and after that, the user experience is smooth.
Upvotes: 0
Reputation:
Put add a few objects to the scene per frame over time. Three.js inits WebGL resources on first use so if there's 100 objects on your scene all 100 objects get initialized the first time you call renderer.render
.
So, just put N objects to the scene, call renderer.render
, then next frame add N more to the scene, etc until all the objects have been added.
It's probably most important to do it by material and geometry. In other words if you have 10 different materials and 10 different geometries and you're rendering 100 different models (a model takes one material and one geometry), then you want to make sure the first N models you add don't use all the materials and all the models because those are the things that need to get initialized.
Post processing passes also need initialization so if you're using any of those maybe the first frame just init those, then start adding objects.
Upvotes: 2