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,

Другие вопросы по тегам