Callback after scene is completely ready

Hello,

do we have the possibility with threejs to retrieve a callback once the scene is ready?

With Babylon there are the functions isReady and executeWhenReady:

This function will check if the scene can be rendered (textures are loaded, shaders are compiled). Delay loaded resources are not taking in account.

This is because I use rendering on demand, and when the scene changes, I don’t want to render again until everything is really ready. So not only all textures should be loaded, but also all materials compiled, objects repositioned, etc.

Is there a way to implement this?

Best

let’s turn it around, how can you not know that your scene is ready? you are the one that’s loading these assets, you need to commit a mistake in order for you to not know when they’ve finished loading/parsing. imo this indicates an architecture problem, good architecture flows one-way, top-down, uniformly, when you arrive at the bottom your app is ready to respond.

Fair enough. I am already waiting until all textures are loaded but this still leads to the situation that the model is white for a few milliseconds until it receives its material. How can I avoid this?

In addition to that is there another way in r3f to pause the rendering without changing the frameloop prop of Canvas?

If you’re using a shared LoadingManager for everything, you can use its callbacks to know when those things have loaded. You may (optionally) want to precompile shaders and upload textures to the GPU using methods on the renderer.

In general three.js loaders return objects that already have materials and textures. If you’re modifying materials in code after that, you’ll need to include that in your setup timing.

if you use fiber then loading is taken care of, you control the succession of things with suspense, if everything is inside the same suspense bound than all components will render together once everything has loaded. say you have a model, a texture and an environment map inside <Suspense> then it would be impossible for the model to come before the envmap, or the envmap before the model, they’ll all go live in sync.

can you show me how you load the texture and apply it to the material? bc drei/useTexture goes out of its way to have everything ready without FOUC, it pre-uploads the images to the gpu.

1 Like

I tried useTextures but I ended up creating my own hook. I am still testing a few things. I will come back to this later.

Okay, now I wrapped my whole scene with <Suspense> like this:

return (
    <Canvas>
        <Suspense fallback={null}>
            ...
        </Suspense>
    </Canvas>
)

That worked indeed. I noticed a limitation though. Since my scene is not static I load some models conditionally. To accomplish that I lazy load the model (created with gltf2jsx).

const Model = useMemo(() => lazy(() => import('model.js')), [])

return <Model />

This breaks until I wrap it also with <Suspense> like this:

const Model = useMemo(() => lazy(() => import('model.js')), [])

return (
    <Suspense fallback={null}>
        <Model />
    </Suspense>
)

Unfortunately now the scene doesn’t wait anymore for the model to be ready. For example if I wrap <Bounds> around the model the camera is not targeting the model on first render. How am I able to wait for the scene to be ready even though I am lazy loading my model?

Late reply but you solve that by lazy loading the components with lazy from React. Doing so slots it into the Suspense model and idiomatic React loading patterns now apply.

See: lazy – React