Is it enough to delete the MeshBasicMaterial object when replacing an image loaded via TextureLoader from a URL?

In my world I build walls that are actually cubes but with one side made very small (so it’s no longer a cube but it looks like a wall/panel). One and only one face of the cube gets an image assigned to it, loaded via aTHREE.TextureLoader().load() call using a URL to a JPG file.

I want to be able to update the images of a wall. Is it enough just to delete the existing MeshBasicMaterial object assigned to the surface of the cube that has the image object, and replace it with a new one received from another call to THREE.TextureLoader().load()? Or are there other steps I need to take to make sure I clean up memory property? I’ll be replacing images a lot so I need to be really diligent in this if I want to avoid memory leaks.

Note: If there is an overall easier, faster, or safer way to replace the image of an object from a URL, please let me know!

This is the code I use to replace an asset now. Is it correct and is it enough to completely clean up an earlier loaded MeshBasicMaterial instance?

        // If there is an existing asset, then remove it.
        if (self[surfaceName] && self[surfaceName].materialContent !== null) {
            // Is it a ThreeJS object or any other object that has a dispose method?
            if (typeof self[surfaceName].materialContent.dispose !== undefined)
                // Yes. Call its dispose method.
                self[surfaceName].materialContent.dispose();
        }

Below is the code I use to create the material for a wall in the first place:

/**
 * Given a URL to an image, build a ThreeJS texture from it.
 *
 * @param {String} srcUrl - A URL to an image.
 * @param {Boolean} bIsRepeated - Whether or not the texture should be repeated.
 * @param {Object} theTexture - A ThreeJS texture object.
 *
 * @return {MeshBasicMaterial} - Returns a ThreeJS MeshBasicMaterial object
 *  built from the image at the given URL.
 */
function createMaterialFromImage(srcUrl, bIsRepeated=false) {
    const errPrefix = `(createMaterialFromImage) `;

    if (misc_shared_lib.isEmptySafeString(srcUrl))
        throw new Error(errPrefix + `The srcUrl parameter is empty.`);
    // Make sure an attempt to load a GIF file is not made with
    //  this function.
    if (srcUrl.toLowerCase().endsWith('.gif'))
        throw new Error(errPrefix + `The srcUrl parameter is a GIF file: ${srcUrl}.`);

    if (typeof bIsRepeated !== 'boolean')
    	throw new Error(errPrefix + `The value in the bIsRepeated parameter is not boolean.`);

    const threeJsMaterial = new THREE.MeshBasicMaterial();

    if (bVerbose) {
        console.info(`${errPrefix}Loading image: ${srcUrl}.`);
    }

    const loader = new THREE.TextureLoader().load(
        // resource URL
        srcUrl,
        // This function fires when the resource is loaded.
        function ( theTexture ) {
            // If the image is to be repeated, set the wrap
            //  properties to THREE.RepeatWrapping, otherwise
            //  use the default wrapping which is THREE.ClampToEdgeWrapping.
            theTexture.wrapS = bIsRepeated ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
            theTexture.wrapT = bIsRepeated ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;

            // Assign the texture value to the material map when the texture is loaded.
            threeJsMaterial.map = theTexture;

            if (bVerbose)
                console.info(`${errPrefix}Resource LOADED: ${srcUrl}.`);
        },
        // This function will be called as the download of an
        //  image progresses.
        function ( xhr ) {
            if (bVerbose) {
                const pctLoaded = xhr.loaded / xhr.total * 100;

                console.info(`${errPrefix}${pctLoaded}}% loaded.  Resource: ${srcUrl}.`);
            }
        },
        // This function will be called in the event of an error.
        function ( xhr ) {
            console.error( `${errPrefix} Download failed for resource: ${srcUrl}.`);
        }
    );

    // Return the threeJsMaterial we created the desired image.
    return threeJsMaterial;
}

you don’t need to delete the material. just dispose the texture and assign a new one.

1 Like

Thanks. Do I need to set needsUpdate to true on the newly created materials object, to get it render properly on the next animate loop pass?