我正在使用GLTF加载程序在我的场景中加载自定义模型。
我有一个负责加载模型的Spaceship.js
类。
// Spaceship.js
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
export default class Spaceship {
constructor() {
this.GLTFLoader = new GLTFLoader();
this.loadModel(this.GLTFLoader, './spaceship_model.gltf').then(result => {
this.model = result.scene;
});
}
loadModel(loader, url) {
return new Promise((resolve, reject) => {
loader.load(
url,
gltf => {
resolve(gltf);
},
undefined,
error => {
console.error('An error happened.', error);
reject(error);
}
);
});
}
}
以及用作整个三个场景的外壳的类ThreeShell.js
import * as THREE from 'three';
import Spaceship from './Spaceship.js';
export default class ThreeShell {
constructor(container = document.body) {
this.container = container;
this.setup();
}
setup() {
...
this.spaceship = new Spaceship();
console.log(this.spaceship);
console.log(this.spaceship.model);
...
}
}
以某种方式,当登录this.spaceship
时,我得到一个具有model属性的对象。但是当登录this.spaceship.model
时,我得到的是undefined
。
我想这可能与诺言有关,我目前对此不太满意。这就是为什么我要您的帮助。
GLTFLoader异步加载资产。
this.spaceship = new Spaceship(); // Loading begins...
console.log(this.spaceship);
// Doesn't yet exist because it gets executed immediately, before loading has completed
console.log(this.spaceship.model);
如果要访问this.spaceship.model
,则需要从Promise
类的外部使用Spaceship
:
this.spaceship = new Spaceship(); // Don't load in constructor...
console.log(this.spaceship);
// Perform load call here
this.spaceship.loadModel().then((result) => {
// Now GLTF will exist here because you're waiting
// for the asynchronous callback
console.log(result.scene);
});
[您似乎已经很了解Promise
的工作原理,但是here's a bit of further clarification。
正如Marquizzo所说,模型是异步加载的,所以这些行
this.spaceship = new Spaceship();
console.log(this.spaceship.model);
不会工作。有很多方法可以解决此问题。
另一个可能是添加一个等待函数,该函数返回加载承诺并使用异步函数来等待它
// Spaceship.js
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
export default class Spaceship {
constructor() {
this.GLTFLoader = new GLTFLoader();
this._loadingPromise = this.loadModel(this.GLTFLoader, './spaceship_model.gltf').then(result => {
this.model = result.scene;
});
}
waitForLoad() {
return this._loadingPromise;
}
loadModel(loader, url) {
return new Promise((resolve, reject) => {
loader.load(
url,
gltf => {
resolve(gltf);
},
undefined,
error => {
console.error('An error happened.', error);
reject(error);
}
);
});
}
}
然后在设置中
import * as THREE from 'three';
import Spaceship from './Spaceship.js';
export default class ThreeShell {
constructor(container = document.body) {
this.container = container;
this.setup();
}
async setup() {
...
this.spaceship = new Spaceship();
console.log(this.spaceship);
await this.spaceship.waitForLoad();
console.log(this.spaceship.model);
...
}
}
我并不是说这是好是坏,只是指出还有更多方法,您不必将加载移出构造函数。
您也可以这样做
setup() {
...
this.spaceship = new Spaceship();
console.log(this.spaceship);
this.spaceship.waitForLoad().then(() => {
console.log(this.spaceship.model);
});
...
}