Completely destroy scene and recreate new one

Hello guys,
I’m struggling with the issue to “destroy” existing scene (scene, renderer, objects, materials…) and create new, “fresh one”.
Which entities to dispose, delete, set to null ? I’ve tried to cancelAnimationFrame, dispose all objects and materials, dispose renderer, set scene to null. Despise that, after 3-4 attempts of destroying and recreating, application crashes with the Error (THREE.WebGLProgram: Shader Error 0 - VALIDATE_STATUS false) .

Thanks in advance!

Reload Page.

Without reloading page.

Then provide something: ( code, link , console log, … )

Okay. I use THREE JS library in Angular application, and 3D scene is created when the lifecycle hook “ngAfterViewInit” is called. In that lifecycle hook, 4 methods are defined.

this._scene = new THREE.Scene();

this.load3dObjects();
this.addLights();
this.addCamera();
this.startRenderingLoop();

3D objects are loaded from the obj.file and added to the scene. Then I add lights and postion camera, it is quite simple configuration. I think that the problem lies with the startRenderingLoop.

private startRenderingLoop() {

    // *** Renderer
    this.createRenderer();

    const component: DigitalTwinComponent = this;

    (function render()  {
      cancelAnimationFrame(component.digitalTwinService.rendererID)
      component.digitalTwinService.rendererID = requestAnimationFrame(render);
      component.autoRotateCamera();
      component._controls.update();

      component._raycaster.setFromCamera(component._mouse, component._camera);
      const intersects = component._raycaster.intersectObjects(component._scene.children);

      // *** Highlight 3D object on hover
      if (intersects.length > 0) {
        if (component.intersected !== intersects[0].object) {
          if (component.intersected) {
            component.intersected.material.color.setHex(component.intersected.currentHex);
          }
          let i = intersects.length

          if (intersects[0].object.visible === true)
            component.intersected = intersects[0].object;
          else
            component.intersected = intersects[i-1].object;
          component.intersected.currentHex = component.intersected.material.color.getHex();
          component.intersected.material.color.setHex(0xff0000);
        }
      } else {
        if (component.intersected) {
          component.intersected.material.color.setHex(component.intersected.currentHex);
        }
        component.intersected = null;
      }

      component._renderer.clear();
      component._renderer.render(component._scene, component._camera);
    }());
  }
private createRenderer() {
    this._renderer = new THREE.WebGLRenderer({ canvas: this._canvasRef.nativeElement, antialias: true });
    this._renderer.shadowMap.enabled = true;
    this._renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    this._renderer.setPixelRatio(devicePixelRatio);
    this._renderer.setSize(this._canvasRef.nativeElement.clientWidth, this._canvasRef.nativeElement.clientHeight);

    this._controls = new OrbitControls(this._camera, this._renderer.domElement);
    this._controls.update();
  }

So whenever this component is initialized, these methods are called. So I’ve tried to clean the scene and renderer (if they exist) before these methods are called. I’ve used this code.

clear(){
    this._renderer.dispose()
    this.stopAnimation()

    this._scene.traverse(object => {
      if (!object.isMesh) return
      
      this.deleteObject(object)
    })
  }

private deleteObject(object: THREE.Object){
    object.geometry.dispose()

    if (object.material instanceof Array) {
      object.material.forEach(material => material.dispose());
    } else {
        object.material.dispose();
    }
    object.removeFromParent()
    this._scene.remove(object)
  }

For reference — How to Dispose of Objects.

Could you share a demo? The code looks reasonable but is missing chunks and isn’t enough to reproduce the error.

Hello, You can find demo here: Angular 11 New (forked) - StackBlitz.

It’s not the same as the application, but it implements similar logic. There you can find, 3D simulation, and two buttons, one to “clear scene” and other to “create new one”.
I know there is an option to clear all the objects from the scene and add new ones, but I don’t want to do that !

As I’ve mentioned above, in the application, 3D setup is created on component load. Every time component loads, variables defined in component are reinitialized again, and procedure for creating 3D setup begins. The problem is that I can’t clear “previous setup” on load, and that causes application to crash.

I m also wondering what happens with 3D setup (scene, render) when user goes to other page in the same application?

So what is my goal here?

So when user clicks button “Clear Everything”, scene, objects, render should be destroyed or set to undefined (same as when application builds for the first time). After user has clicked “Clear Everything”, and it clicks “Start new Scene”, a new Scene should emerge.

This seems pretty simple request, create 3D setup, destroy it, and recreate it.

Thanks in advance guys !

Important notice.

Application (not one displayed in Demo) works properly while using Mozilla Firefox, it doesn’t crash or create errors. On the other hand, application crashes while using Chrome and Edge.

any solution?

2018 solutions don’t seem to clean up, memory and gpu usage are still there, even if I destroy the dom,
if I destroy and then create repeatedly, the memory overflows

If you create 32 scenes (last I checked in Chrome) before the GC collects the webgl contexts, the new contexts will not work. Maybe that’s the issue you are seeing?

The dispose methods do not actually free memory, they just unreference things so that, eventually, the collector will free the memory. But until the memory is freed, the webgl limit will apply.

Depending on your use case, there may be alternative solutions, like rendering multiple scenes using a single canvas.

2 Likes

https://threejs.org/docs/#api/en/renderers/WebGLRenderer.forceContextLoss

Additionally - do the official examples also cause memory leaks in your browser? If yes, that’s a base for a bug report. If not, it’s possible memory leak is caused by your custom code?

yes,there is no problem with this example, the object references parsed from a huge compressed gltf model file are much more complex and are referenced everywhere. It may be a problem in my program, but it is not easy to troubleshoot. It is very difficult to test hundreds or thousands of objects, using multiple scenes seems like a good approach

That’s probably a bigger issue than the scene disposal - in a long run, you’ll end up with memory leaks, so it may be a good idea to fix it up asap (model geometries, besides the loading process, are no more complex than box or sphere geometries - they just have more vertices on the GPU. Make sure you’re not storing them in random arrays and objects, and if you are - dispose those arrays and objects together with the scene.)

ok, this is a meticulous job.