我正在使用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()完成?
答案 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))