5

I load an image to show a sprite.

But it seems that the code proceeds before the image is fully load:

But I don't know how to wait for the image to be fully loaded using Threejs. May I have some help?

The code can be tested here : http://www.planetarium2016.com/sprite.html

Here is my code:

<html>
    <head>
        <title>My first three.js app</title>
        <style>
            body { margin: 0; }
            canvas { width: 100%; height: 100% }
        </style>
    </head>
    <body>
        <script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script>
        <script>
            var scene = new THREE.Scene();
            var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);
            camera.position.set(0, 10, 100);
            camera.lookAt(new THREE.Vector3(0, 0, 0));
            var renderer = new THREE.WebGLRenderer();
            renderer.setSize( window.innerWidth, window.innerHeight );
            document.body.appendChild( renderer.domElement );

            var material = new THREE.LineBasicMaterial({ color: 0x0000ff });
            var geometry = new THREE.Geometry();
            geometry.vertices.push(new THREE.Vector3(-10, 0, 0));
            geometry.vertices.push(new THREE.Vector3(0, 10, 0));
            geometry.vertices.push(new THREE.Vector3(10, 0, 0));
            geometry.vertices.push(new THREE.Vector3(0, 0, -10));

            var line = new THREE.Line(geometry, material);

            scene.add(line);

            var loader = new THREE.TextureLoader();
            var spriteMap = loader.load("https://codefisher.org/static/images/pastel-svg/256/bullet-star.png");

            //+-----------------------------------------------------------+
            //|   I need here to wait for the image to be fully loaded    |
            //|   This cheat is fool: while (spriteMap.image.width == 0); |
            //+-----------------------------------------------------------+

            var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap, color: 0xffffff } );
            var sprite = new THREE.Sprite( spriteMaterial );
            sprite.scale.set(256, 256, 1);
            sprite.position.set( 0, 0, 10 );
            scene.add( sprite );

            //camera.position.z = 2;

            var render = function () {
                requestAnimationFrame( render );
                renderer.render(scene, camera);
            };
            render();
        </script>
    </body>
</html>

THREE JS TextureLoader is a little bit old...

Community
  • 1
  • 1

3 Answers3

7

I would solve this by using JavaScript promises. I separated your three.js code into two main functions, one for initialization and one for animation with requestAnimationFrame. It's more readable this way especially if you intend to perform an async task:

        var scene;
        var camera;
        var renderer;

        var spriteMap;

        var loaderPromise = new Promise(function(resolve, reject) {
            function loadDone(x) {
                console.log("loader successfully completed loading task");
                resolve(x); // it went ok!
            }
            var loader = new THREE.TextureLoader();
            loader.load("https://codefisher.org/static/images/pastel-svg/256/bullet-star.png", loadDone);
        });

        loaderPromise.
            then(function(response) {
                spriteMap = response; //assign loaded image data to a variable
                init(); //initialize the render
                requestAnimationFrame( render );
            }, function(err) {
                console.log(err);
            });

        function init() {
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);

            camera.position.set(0, 10, 100);
            camera.lookAt(new THREE.Vector3(0, 0, 0));

            renderer = new THREE.WebGLRenderer();
            renderer.setSize( window.innerWidth, window.innerHeight );
            document.body.appendChild( renderer.domElement );

            var material = new THREE.LineBasicMaterial({ color: 0x0000ff });
            var geometry = new THREE.Geometry();
            geometry.vertices.push(new THREE.Vector3(-10, 0, 0));
            geometry.vertices.push(new THREE.Vector3(0, 10, 0));
            geometry.vertices.push(new THREE.Vector3(10, 0, 0));
            geometry.vertices.push(new THREE.Vector3(0, 0, -10));

            var line = new THREE.Line(geometry, material);
            scene.add(line);

            var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap, color: 0xffffff } );
            var sprite = new THREE.Sprite( spriteMaterial );
            sprite.scale.set(256, 256, 1);
            sprite.position.set( 0, 0, 10 );
            scene.add( sprite );
        }

        function render() {
            renderer.render(scene, camera);
            requestAnimationFrame( render );
        }
noviewpoint
  • 574
  • 1
  • 10
  • 20
0

solution here: https://threejs.org/docs/#api/loaders/TextureLoader

this is the code to solve my problem:

        var url = "https://codefisher.org/static/images/pastel-svg/256/bullet-star.png";
        var loader = new THREE.TextureLoader();
        var spriteMaterial;
        loader.load(url,
            function(texture)
                {
                    spriteMaterial = new THREE.SpriteMaterial( { map: texture, color: 0x0000ff } );
                }

            );
        var sprite = new THREE.Sprite( spriteMaterial );
  • thanks for acknowledgment but there is gap in this code. loader.load(url, function(texture) { spriteMaterial = new THREE.SpriteMaterial( { map: texture, color: 0x0000ff } ); } ); var sprite = new THREE.Sprite( spriteMaterial ); //sprteMaterial might be undefined here. Instead do this var spriteMaterial = new THREE.SpriteMaterial( { color: 0x0000ff } ); loader.load(url, function(texture) { spriteMaterial.map = texture; spriteMaterial.needsUpdate = true; } ); – Ajit kohir May 02 '17 at 11:48
  • You are right: I could only show a white square instead of the star.png. But doing your code, I get the same errors as when I didn't wait for the image to be loaded: http://www.planetarium2016.com/sprite.html – Pierre-Louis Deschamps May 02 '17 at 12:01
  • so is this warking or not ? please accept your own answer if yes – Qbik Apr 01 '21 at 07:38
  • Can't tell. It was in 2017! I have to work on a similar code in 2022. I will test it again and update this thread. – Pierre-Louis Deschamps Nov 24 '21 at 13:59
0
var loader = new THREE.TextureLoader();
loader.load(
    'img/url/img.png',
    function ( map ) {
        // map var is your image                                                                      
    }, 
    function ( xhr ) {                                                                                    
        if ( xhr.lengthComputable ) {                                                                                       
           console.log( 'percent: ' + (xhr.loaded / xhr.total * 100) );                                                                                   
        }
    },
    function ( err ) {                                                                                      
       console.log( 'An error happened' );
    }
); 

THREE 73

Rvy Pandey
  • 1,654
  • 3
  • 16
  • 22
Martin
  • 2,575
  • 6
  • 32
  • 53