I'm working with release R73. My current task is to fill an array with materials. The content of this array is supposed to be used later. That usage depends on all materials to me completely loaded.
By now I loop through an array of JSON information and call this code for every element:
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 is initialized earlier: var TLoader = new THREE.TextureLoader();
If a material isn't there, when it is needed, I get a fallback material. This was only intended as an error option. Is there a way to wait until .load() finishes?
Threejs already provides a callback for all elements loaded - via the use of a LoadingManager. By default, TextureLoader uses the 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,"!"));
That's going to wait for all assets to load, though. If you want to be listening for a specific subset of assets loaded, you can do that by constructing a custom LoadingManager and passing it into your TextureLoader to manage different asset bundles separately:
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,"!"));
You can also use this simple helper if you need to load multiple textures before rendering your scene :
/**
*
* @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)
)
})
})
}
Then wrap your code using Promise.all
, allowing to fetch the sources in parallel, and fail properly by catching the error.
Example :
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))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With