Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js - how to wait for a image to be loaded?

I load an image to show a sprite.

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

  • dart:web_gl: RENDER WARNING: texture bound to texture unit 0 is not renderable

  • WebGL - wait for texture to 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...

like image 536
Pierre-Louis Deschamps Avatar asked May 02 '17 08:05

Pierre-Louis Deschamps


1 Answers

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 );
        }
like image 198
noviewpoint Avatar answered Nov 19 '22 03:11

noviewpoint