Three.js 从 ObjLoader 操作一个对象
Three.js Manipulate an object from ObjLoader
我正在尝试操作(例如更改位置、缩放、旋转)在 Three.js 中使用 OBJLoader 加载的对象。虽然这一次很容易做到,但我不知道如何在我想要的时候做到这一点,例如在动画循环期间,或初始加载回调之外的任何地方。
这是我的代码:
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 加载器尝试了类似的代码,得到了相同的结果(我能够在加载过程中操作它,但之后不能)。
THREE.js
中的加载器是异步的,因此最好的解决方法是简单地使用 Promise
,或使用新的 await。这是承诺的实现。我只是将所有 THREE.js
加载程序代码包装在 promise 中并在最后调用 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
.
我正在尝试操作(例如更改位置、缩放、旋转)在 Three.js 中使用 OBJLoader 加载的对象。虽然这一次很容易做到,但我不知道如何在我想要的时候做到这一点,例如在动画循环期间,或初始加载回调之外的任何地方。
这是我的代码:
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 加载器尝试了类似的代码,得到了相同的结果(我能够在加载过程中操作它,但之后不能)。
THREE.js
中的加载器是异步的,因此最好的解决方法是简单地使用 Promise
,或使用新的 await。这是承诺的实现。我只是将所有 THREE.js
加载程序代码包装在 promise 中并在最后调用 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
.