Search code examples
javascriptthree.jstextures

Proper way to update texture (THREE.JS)


I have some checkbox booleans that load different textures to a sphere in three.js.

I am running into the issue of these images not loading fast enough, causing some drag on performance. I imagine I will need to preload them but not sure the best way for that. I am also including my current code as there may be a better solution altogether or some unneeded code of mine.

function showPoliticalMap(){
    var world = scene.getObjectByName("world").children[1],
        cloud = scene.getObjectByName("cloud"),
        uri = world.material.map.image.baseURI;

    scene.remove(cloud);
    spotlight.intensity = 0;
    ambientLight.intensity = 1;
    world.material.map.image.currentSrc = uri + "img/earthmapoutlineblue_optimized.jpg";
    world.material.map.image.src = uri + "img/earthmapoutlineblue_optimized.jpg";
    world.material.map.needsUpdate = true;
    world.material.needsUpdate = true;
}

Solution

  • If you want to remove clouds and change light intensity after the texture has been changed, then you need to load the texture before. You can use the TextureLoader for this, check the documentation. In the example below you dont really need the download progress callback, but the error callback could be good to keep.

    function showPoliticalMap(){
        var world = scene.getObjectByName("world").children[1],
            cloud = scene.getObjectByName("cloud"),
            uri = world.material.map.image.baseURI;
    
        // instantiate a loader
        var loader = new THREE.TextureLoader();
    
        // load a resource
        loader.load(
            // resource URL
            uri + "img/earthmapoutlineblue_optimized.jpg",
            // Function when resource is loaded
            function ( texture ) {
                // do something with the texture
                world.material.map = texture;
                world.material.needsUpdate = true;
    
                scene.remove(cloud);
                spotlight.intensity = 0;
                ambientLight.intensity = 1;
            },
            // Function called when download progresses
            function ( xhr ) {
                console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
            },
            // Function called when download errors
            function ( xhr ) {
                console.log( 'An error happened' );
            }
        );
    }
    

    I haven't tested it so not sure if it will work directly, but it shows the principle of it anyway.