Three.js Управляет объектом из ObjLoader
Я пытаюсь манипулировать (например, изменить положение, масштаб, вращение) объекта, загруженного с использованием OBJLoader в Three.js. Хотя это легко сделать один раз, я не могу понять, как это сделать, когда я хочу, например, во время цикла анимации или где-нибудь за пределами первоначального обратного вызова загрузки.
Вот мой код:
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;
Ключевые моменты, на которые следует обратить внимание:
- Я могу загрузить его и манипулировать им внутри цикла нормально, и никаких ошибок не возникает;
- Если я сделаю выше, я получу ошибку в последней строке, которая гласит:
Cannot read property 'position' of undefined
, - Эта ошибка остается, если я определю
obj
вне функции (как глобальная), а затем ссылаться на нее соответственно.
Я пробовал подобный код с загрузчиком JSON, к тем же результатам (я могу манипулировать им в нагрузке, но не после).
1 ответ
Погрузчики в THREE.js
являются асинхронными, поэтому лучший способ обойти это просто использовать Promise
или используйте новое ожидание. Вот обещание реализации. Я просто завернул все THREE.js
код загрузчика внутри обещания и вызова resolve
в конце. Тогда просто используйте .then
выполнять всякий раз, когда выполняется асинхронный запрос.
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;
});
Обновление Исправлена небольшая ошибка, где это будет reject
в то время как onProgress
, Мой Плохой, прочитал еще раз документы THREE.js и заметил, что порядок load
является url, onSuccess, onProgress, onError
итак финал должен быть url, resolve, () => {}, reject
,