Three.js - 如何等待图片加载完成?

5

我加载了一张图片来显示一个精灵。

但是似乎代码在图片完全加载之前就继续执行了:

但是我不知道如何使用Threejs等待图像完全加载。

可以在此处测试代码:http://www.planetarium2016.com/sprite.html

这是我的代码:

<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有点过时了...


1
可能是THREE JS TextureLoader的重复问题。 - StudioTime
var textureLoader = new THREE.TextureLoader(); textureLoader.load(url,function(){ //在此处编写逻辑。 }); 请查看TextureLoader类文档。 - Ajit kohir
@darren-sweeney 这些旧的问题和答案已经过时了。 - Pierre-Louis Deschamps
@kian没错:https://threejs.org/docs/#api/loaders/TextureLoader - Pierre-Louis Deschamps
@Pierre-LouisDeschamps 哦,好的,我的重点主要是强调 .load 回调函数,你现在正在使用它。 - StudioTime
@darren-sweeney,你的评论和http://stackoverflow.com/questions/14010165/three-js-textureloader帮助我解决了我的问题。 - Pierre-Louis Deschamps
3个回答

7
我会使用JavaScript Promise来解决这个问题。我将你的three.js代码分成了两个主要函数,一个用于初始化,另一个用于使用requestAnimationFrame进行动画。这样做更易读,特别是如果你打算执行异步任务:
        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 );
        }

如何将其扩展为可用于加载多个对象的加载器? - lowlyprogrammer
1
创建一个对象数组,并使用 Promise.all 等待它们全部加载完成后再调用 init() 方法。 - noviewpoint

0

解决方案在这里:https://threejs.org/docs/#api/loaders/TextureLoader

这是解决我的问题的代码:

        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 );

感谢您的认可,但是这段代码存在问题。loader.load(url, function(texture) { spriteMaterial = new THREE.SpriteMaterial( { map: texture, color: 0x0000ff } ); } ); var sprite = new THREE.Sprite( spriteMaterial ); // 这里可能会出现spriteMaterial未定义的情况。可以改为以下方式:var spriteMaterial = new THREE.SpriteMaterial( { color: 0x0000ff } ); loader.load(url, function(texture) { spriteMaterial.map = texture; spriteMaterial.needsUpdate = true; }); - Ajit kohir
你是对的:我只能显示一个白色正方形,而不是 star.png。但是使用你的代码,我得到了与在图像加载完成之前不等待时相同的错误: http://www.planetarium2016.com/sprite.html - Pierre-Louis Deschamps
这个程序是否正常工作?如果是,请接受您自己的答案。 - Qbik
不好说,那是在2017年!我得在2022年再次处理类似的代码。我会重新测试并更新这个线程。 - Pierre-Louis Deschamps

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' );
    }
); 

三 73


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接