有没有办法等待THREE.TextureLoader.load()完成?

时间:2015-10-22 14:23:14

标签: javascript three.js

我正在使用R73版本。 我目前的任务是用数据填充数组。该数组的内容应该在以后使用。这种用法取决于我完全装载的所有材料。

到现在为止,我遍历一个JSON信息数组,并为每个元素调用此代码:

TLoader.load(
        BASE_ODB_URL + jsonMat.pic,
        function (texture) {
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.repeat.set(jsonMat.scaleu, jsonMat.scalev);
            Mat = new THREE.MeshLambertMaterial({
                    map : texture,
                    side : THREE.DoubleSide,
                    name : jsonMat.mname
                });
            THREEMatList.push(Mat);
        },
        function (xhr) {
        }, //onProgress
            function (xhr) {
            Mat = new THREE.MeshLambertMaterial({
                    color : 0xff0000,
                    side : THREE.DoubleSide,
                    name : jsonMat.mname
                });
            THREEMatList.push(Mat);
        } 
    )

先前初始化TLoader:var TLoader = new THREE.TextureLoader();

如果材料不在那里,当需要时,我会得到一个后备材料。这仅用作错误选项。 有没有办法等到.load()完成?

3 个答案:

答案 0 :(得分:3)

解决这个问题的一种方法是通过Promise来解决这个问题,因为它们确实是前进之路,我个人认为这是一种耻辱TextureLoader不会返回{ {1}}开始(这将使这更容易)。但是,请记住,IE11需要一个polyfill,因为它缺乏对promises的原生支持。

这样的事情应该这样做,其中Promise代表可迭代textureArray中的JSON数据:

Array

所以,这里发生的是一个总体var allPromises = []; textureArray.forEach( function( jsonMat ) { allPromises.push( new Promise( function( resolve, reject ) { TLoader.load( BASE_ODB_URL + jsonMat.pic, function( texture ) { // Success callback of TextureLoader texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( jsonMat.scaleu, jsonMat.scalev ); var material = new THREE.MeshLambertMaterial({ map: texture, side: THREE.DoubleSide, name: jsonMat.mname }); THREEMatList.push( material ); // We're done, so tell the promise it is complete resolve( material ); }, function( xhr ) { // Progress callback of TextureLoader // ... }, function( xhr ) { // Failure callback of TextureLoader // Reject the promise with the failure reject( new Error( 'Could not load ' + jsonMat.pic ) ); } ); })); }); Promise.all( allPromises ) .then( function( arrayOfMaterials ) { // All textures are now loaded, and this array // contains all the materials that you created }, function( error ) { console.error( "Could not load all textures:", error ); }); 用于跟踪其他Promise的状态。正在加载的每个纹理都包含在Promise中,并添加到Promise。最后,对整套承诺进行成功或失败测试,​​并在此时了解整体成功或失败。

这里要记住的一件重要事情是allPromises只有在所有纹理加载后才会成功,并且只要任何一个失败就会失败。如果您需要更好的控制,那么您需要Promise.all polyfill,其功能多于Promise / A +规范提供的功能,例如RSVP.js。或者代替Promise你可以reject()承诺,并优雅地处理结果。

答案 1 :(得分:1)

Threejs已经为所有加载的元素提供回调 - 通过使用LoadingManager。默认情况下,TextureLoader使用DefaultLoadingManager:

import {TextureLoader, DefaultLoadingManager} from './three.module.js';

const getTextures = ()=> new Promise((resolve, reject)=>{
  const loader = new TextureLoader();
  DefaultLoadingManager.onLoad = ()=>resolve(textures);
  const textures = [
    "image1.jpg",
    "image2.jpg",
    "image3.jpg"
  ].map(filename=>loader.load(filename));
});

getTextures().then(result=>console.log("We received,", result,"!"));

但是,等待所有资产加载。如果您想要监听加载的特定资产子集,可以通过构建自定义LoadingManager并将其传递到TextureLoader来分别管理不同的资产包来实现:

import {TextureLoader, LoadingManager} from './three.module.js';

const getTextures = ()=> new Promise((resolve, reject)=>{
  const manager = new LoadingManager(()=>resolve(textures));
  const loader = new TextureLoader(manager);
  const textures = [
    "image1.jpg",
    "image2.jpg",
    "image3.jpg"
  ].map(filename=>loader.load(filename));
});

getTextures().then(result=>console.log("We received,", result,"!"));

答案 2 :(得分:1)

如果需要在渲染场景之前加载多个纹理,也可以使用这个简单的帮助器:

    /**
     *
     * @param {Array} texturesSources - List of Strings that represent texture sources
     * @returns {Array} Array containing a Promise for each source 
     */
    function getTextures (texturesSources) {
        const loader = new THREE.TextureLoader()
        return texturesSources.map(textureSource => {
            return new Promise((resolve, reject) => {
                loader.load(
                    textureSource,
                    texture => resolve(texture),
                    undefined, // onProgress callback not supported from r84
                    err => reject(err)
                )
            })
        })
    }

然后使用Promise.all包装您的代码,允许并行获取源,并通过捕获错误正确地失败。

示例:

const texturesBasePath = '../assets/textures/'
const texturesSRC = [
    'image1.jpg',
    'image2.jpg',
    'image3.jpg',
].map(texture => texturesBasePath + texture)

Promise.all(getTextures(texturesSRC))
    .then(textures => {
        // create your materials, meshs...
        // render the scene
    })
    .catch(err => console.error(err))