I am trying to manipulate (e.g. change position, scale, rotation) an object loaded using OBJLoader in Three.js. While this is easy to do so once, I cannot work out how to do this when I want e.g. during the animate loop, or anywhere outside of the initial load callback.
Here is my code:
function loadObj( path, name )
{
var obj;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( path );
mtlLoader.load( name+".mtl", function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( path );
objLoader.load( name+".obj", function( object ) {
obj = object;
obj.position.x = 20;
scene.add( obj );
});
});
return obj;
}
var myObj = loadObj( "assets/", "test" );
myObj.position.y = 20;
The key points to note here are:
Cannot read property 'position' of undefined
.obj
outside the function (as a global), and then reference it accordingly.I've tried similar code with the JSON loader, to the same results (I am able to manipulate it within the load, but not afterwards).
Loaders in THREE.js
are asynchronous, so the best way around this is to simply use a Promise
, or use the new await. Heres the promise implementation. I simply wrapped all the THREE.js
loader code inside the promise and call resolve
at the end. Then just use .then
to execute whenever the asynchronous request is done.
function loadObj( path, name ){
var progress = console.log;
return new Promise(function( resolve, reject ){
var obj;
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( path );
mtlLoader.load( name + ".mtl", function( materials ){
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( path );
objLoader.load( name + ".obj", resolve, progress, reject );
}, progress, reject );
});
}
// This way you can use as many .then as you want
var myObjPromise = loadObj( "assets/", "test" );
myObjPromise.then(myObj => {
scene.add( myObj );
myObj.position.y = 20;
});
Update Corrected a little mistake where it would reject
while onProgress
. My Bad, read the THREE.js docs again and noticed that the order of load
is url, onSuccess, onProgress, onError
, so the final should be url, resolve, () => {}, reject
.