scene.removeLight(light) vs light.dispose()

There are two ways to remove a light source from a scene. One is to call the dispose() method on the light object:

this.light = new BABYLON.Light()
this.light.dispose()

The other way is to pass the light source as a parameter to the removeLight(light) method of the scene:

this.scene.removeLight(this.light)

Both methods remove the light from the scene. The question is whether they are equivalent in their effect. Can I use removeLight knowing that memory will be freed and the light object will be deleted just as it would be when using dispose()?

Why am I asking? I encountered a situation where, when I remove a light source using dispose(), the entire scene flickers, and objects are redrawn.
However, when I remove the light source using removeLight, the scene does not flicker, and everything remains smooth.
Through the Inspector, I can see that both methods remove the light source from the Nodes.

For the expert advise, I’d wait for cc @Evgeni_Popov
Else, my two cents are that it is the same as with some others (pre or post fx). It has something to do with the rendering order. Removing a light will affect early loaded and applied properties such as for i.e. PBR materials. I believe removing light is similar to ‘setEnabled’ or ‘isVisible’, whereas ‘dispose’ de facto excludes it from any processing. As I said, my two cents only.

Usually dispose() removes the object resources from memory, so you would dispose when you don’t plan to use it again (or don’t mind recreating it). removeLight() will keep the object in memory for later addLight(). This is quicker than if you had to recreate the light.

But you don’t have to take my word for it! It’s in the source code.

/**
 * Remove a light for the list of scene's lights
 * @param toRemove defines the light to remove
 * @returns the index where the light was in the light list
 */
public removeLight(toRemove: Light): number {
    const index = this.lights.indexOf(toRemove);
    if (index !== -1) {
        // Remove from meshes
        for (const mesh of this.meshes) {
            mesh._removeLightSource(toRemove, false);
        }

        // Remove from the scene if mesh found
        this.lights.splice(index, 1);
        this.sortLightsByPriority();

        if (!toRemove.parent) {
            toRemove._removeFromSceneRootNodes();
        }
    }
    this.onLightRemovedObservable.notifyObservers(toRemove);
    return index;
}    /**
 * Remove a light for the list of scene's lights
 * @param toRemove defines the light to remove
 * @returns the index where the light was in the light list
 */
public removeLight(toRemove: Light): number {
    const index = this.lights.indexOf(toRemove);
    if (index !== -1) {
        // Remove from meshes
        for (const mesh of this.meshes) {
            mesh._removeLightSource(toRemove, false);
        }

        // Remove from the scene if mesh found
        this.lights.splice(index, 1);
        this.sortLightsByPriority();

        if (!toRemove.parent) {
            toRemove._removeFromSceneRootNodes();
        }
    }
    this.onLightRemovedObservable.notifyObservers(toRemove);
    return index;
}

And here’s dispose():

/**
 * Releases resources associated with this node.
 * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
 * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
 */
public override dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
    if (this._shadowGenerators) {
        const iterator = this._shadowGenerators.values();
        for (let key = iterator.next(); key.done !== true; key = iterator.next()) {
            const shadowGenerator = key.value;
            shadowGenerator.dispose();
        }
        this._shadowGenerators = null;
    }

You can explore the code for the specific type of light to see what other resources it has.

4 Likes