Javascript 三个gltf返回未定义

Javascript 三个gltf返回未定义,javascript,promise,three.js,this,gltf,Javascript,Promise,Three.js,This,Gltf,我正在使用GLTF加载程序加载场景中的自定义模型 我有一个classSpaceship.js负责加载模型 //Spaceship.js 从'three/examples/jsm/loaders/GLTFLoader.js'导入{GLTFLoader}; 导出默认类宇宙飞船{ 构造函数(){ this.GLTFLoader=新的GLTFLoader(); this.loadModel(this.GLTFLoader'./spaceship_model.gltf')。然后(结果=>{ this.mo

我正在使用GLTF加载程序加载场景中的自定义模型

我有一个class
Spaceship.js
负责加载模型

//Spaceship.js
从'three/examples/jsm/loaders/GLTFLoader.js'导入{GLTFLoader};
导出默认类宇宙飞船{
构造函数(){
this.GLTFLoader=新的GLTFLoader();
this.loadModel(this.GLTFLoader'./spaceship_model.gltf')。然后(结果=>{
this.model=result.scene;
});
}
loadModel(加载器,url){
返回新承诺((解决、拒绝)=>{
装载机(
网址,
gltf=>{
决心(gltf);
},
未定义,
错误=>{
console.error('发生错误',error);
拒绝(错误);
}
);
});
}
}
还有一个类
ThreeShell.js
作为整个三个场景的shell

import*作为“三”中的三;
从“./Spaceship.js”导入Spaceship;
导出默认类ThreeShell{
构造函数(容器=document.body){
this.container=容器;
这个.setup();
}
设置(){
...
this.spaceship=新宇宙飞船();
console.log(这是宇宙飞船);
console.log(this.spaceship.model);
...
}
}
不知何故,当记录this.spaceship时,我得到了一个具有model属性的对象。 但是当记录
this.spaceship.model
时,我得到了
未定义的


我想这可能与承诺有关,目前我对此感到不舒服。这就是我请求您帮助的原因。

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);
如果您想访问
这个.spaceship.model
,您需要在
太空船
课程之外使用
承诺

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
s的工作原理,但是。

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);
如果您想访问
这个.spaceship.model
,您需要在
太空船
课程之外使用
承诺

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的工作原理,但是正如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);
    });

    ...
  }

正如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);
    });

    ...
  }

是的,我认为这是一个解决办法。但是我想抽象掉加载程序,这样它就不会妨碍我的主文件。非常感谢。是的,我认为这是一个解决办法。但是我想抽象掉加载程序,这样它就不会妨碍我的主文件。非常感谢。工作起来很有魅力!现在,我知道这只是一个品味的问题,但你会如何进一步把它抽象出来呢?是否无法初始化类并直接获取加载的模型?还是
GLTFLoader
阻止我们这么做?我不知道你在问什么。我当然会把装载机从宇宙飞船上搬走,也会把装载机模型搬出宇宙飞船。它们都没有提到宇宙飞船上的任何东西。尽管您需要等待模型加载,但还是以这种或那种方式。要么通过回调、承诺、异步/等待来实现。这取决于你。如果我不清楚,很抱歉,我是问是否有一种方法可以在类内加载模型,而不必在类外调用方法
waitForLoad
。我想这会更有意义,让代码更清晰。所以你会建议让一个新类负责加载一个模型?然后在宇宙飞船内部使用它?若宇宙飞船控制了所有关于模型的信息,那个么就并没有理由访问宇宙飞船外部的模型。宇宙飞船可以加载模型,将其添加到场景中,并对其进行完整处理。我猜这是假设您正在调用spaceshipInstance.update,或者在渲染循环中像一个符咒一样工作!现在,我知道这只是一个品味的问题,但你会如何进一步把它抽象出来呢?是否无法初始化类并直接获取加载的模型?还是
GLTFLoader
阻止我们这么做?我不知道你在问什么。我当然会把装载机从宇宙飞船上搬走,也会把装载机模型搬出宇宙飞船。它们都没有提到宇宙飞船上的任何东西。尽管您需要等待模型加载,但还是以这种或那种方式。要么通过回调、承诺、异步/等待来实现。这取决于你。如果我不清楚,很抱歉,我是问是否有一种方法可以在类内加载模型,而不必在类外调用方法
waitForLoad
。我想这会更有意义,让代码更清晰。所以你会建议让一个新类负责加载一个模型?然后在宇宙飞船内部使用它?若宇宙飞船控制了所有关于模型的信息,那个么就并没有理由访问宇宙飞船外部的模型。宇宙飞船可以加载模型,将其添加到场景中,并对其进行完整处理。我猜这是假设您正在调用渲染循环中的
spaceshipInstance.update
,或者