Three.js dispose things so hard

Thanks for pointing that out, somehow it completely went over my head, I guess cause I wasn’t using ShaderMaterials at the time, and yes, iterating over the Object.values is better than using a hard-coded list, another great suggestion, so thanks again.

Here is the updated code, also removed the disposeMediaElement method for the sake of simplicity.

import { Object3D, BufferGeometry, Material, Texture, ShaderMaterial } from "three"

/**
 * Dispose of all Object3D`s nested Geometries, Materials and Textures
 *
 * @param object  Object3D, BufferGeometry, Material or Texture
 * @param disposeMedia If set to true will dispose of the texture image or video element, default false
 */
function deepDispose(
  object: Object3D | BufferGeometry | Material | Texture
) {
  const dispose = (object: BufferGeometry | Material | Texture) => 
    object.dispose();
  ;
  const disposeObject = (object: any) => {
    if (object.geometry) dispose(object.geometry);
    if (object.material)
      traverseMaterialsTextures(object.material, dispose, dispose);
  };

  if (object instanceof BufferGeometry || object instanceof Texture)
    return dispose(object);

  if (object instanceof Material)
    return traverseMaterialsTextures(object, dispose, dispose);

  disposeObject(object);

  if (object.traverse) object.traverse((obj) => disposeObject(obj));
}

/**
 * Traverse material or array of materials and all nested textures
 * executing there respective callback
 *
 * @param material          Three js Material or array of material
 * @param materialCallback  Material callback
 * @param textureCallback   Texture callback
 */
function traverseMaterialsTextures(
  material: Material | Material[],
  materialCallback?: (material: any) => void,
  textureCallback?: (texture: any) => void
) {
  const traverseMaterial = (mat: Material) => {
    if (materialCallback) materialCallback(mat);

    if(!textureCallback) return;

    Object.values(mat)
      .filter((value) => value instanceof Texture)
      .forEach((texture) => textureCallback(texture)
    );

    if((mat as ShaderMaterial).uniforms)
      Object.values((mat as ShaderMaterial).uniforms)
        .filter(({ value }) => value instanceof Texture)
        .forEach(({ value }) => textureCallback(value))
  };

  if (Array.isArray(material)) {
    material.forEach((mat) => traverseMaterial(mat));
  } else traverseMaterial(material);
}

export { deepDispose }
1 Like