in my application I have a canvas where I want to switch between different scenes. Some of them are created by using the
VRMLLoader. I am using functional React with TypeScript. By means of the React Hook
useEffect each time I change the data model, the Three.js scene and renderer are disposed and a new scene and renderer is created. That works fine so far, with one exception. Somehow, when I switch from some VRML model back to another model, the scene is missing shadows or only shows distorted shadows.
I don’t understand why this is the case, since all Three.js objects are destroyed and recreated. It almost seems as if Three.js and/or the VRMLLoader has some sort of global side-effect that screws up the shadows. What am I doing wrong?
Here’s a demo:
To reproduce, do this:
- Notice how the knot in the basic model has a shadow.
- Press the “Switch” button in order to load some VRML model.
- Press the “Switch” button again in order to load the original basic model again.
- Notice how the knot’s shadow is gone.
This problem seems to happen only when using
VRMLLoader. When switching between basic models without
VRMLLoader involved, all shadows are as they should be.
I would be grateful for any help.
I’ve ported your code to plain JS (without react and TS) and I can’t reproduce the issue:
Besides, there are some conceptual issues in your code that you should highly avoid:
- Create the renderer just once and reuse it.
- You have to traverse through the VRML scene and set
true for all descendants.
- When changing to a completely different scene, always use
dispose() on all materials, geometries and textures (not just in context of the VRML asset).
- If you remove a renderer and its canvas, stop the animation loop via
Thank you for your reply. I have a couple of follow-up questions:
About reusing the renderer: I assume the renderer should have the same lifetime as the canvas-element, since I specify the canvas either through the renderer classes constructor or let the renderer create its own DOM-element.
So how would I handle that within React where the component recreates the canvas element whenever the component’s properties change? (Is there another answer to this question but “Use Fiber”? )
All “Three.js with React” snippets I’ve found in this forum or via Google handle it like I do. While this doesn’t mean that this is the right way, it seems to work for other people at least.
I’ve added the
scene traversing and calling
dispose() on everything. I’ve also added the
cancelAnimationFrame()call. Still the same issue. See code sandbox:
This is really strange. Maybe it is related to not reusing the renderer.
Sorry, I’m not familiar with React. The only thing I can say is that it’s not really resource efficient to remove and create renderer and its canvas/context over and over again. Resources like that should be allocated once and then reused by the app whenever possible.
Okay. Thanks for all your help and your dedication to this project.