【问题标题】:THREE gltf returns undefined三个 gltf 返回 undefined
【发布时间】:2020-05-22 11:20:41
【问题描述】:

我正在使用 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 时,我得到了一个具有模型属性的对象。 但是当登录this.spaceship.model 时,我得到undefined

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

【问题讨论】:

    标签: javascript promise three.js this gltf


    【解决方案1】:

    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,您需要在Spaceship 类之外使用Promise

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

    看起来您已经很好地掌握了Promises 的工作原理,但是here's a bit of further clarification

    【讨论】:

    • 是的,我认为这是一种解决方法。但我想抽象出加载器,这样它就不会妨碍我的主文件。谢谢!
    【解决方案2】:

    正如 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 阻止我们这样做?
    • 我不确定你在问什么。我当然会把装载机从 Spaceship 和loadModel 移出。这些都没有引用 Spaceship 中的任何内容。尽管您需要等待模型加载,但一种或另一种方式。要么你用回调、承诺、异步/等待来做到这一点。这取决于你。
    • 对不起,如果我不清楚,我在问是否有办法在类内加载模型,而不必在类外调用方法waitForLoad。我在想它会更有意义并使代码更清晰。所以你会建议创建一个负责加载模型的新类?然后在飞船内部使用它?
    • 如果飞船控制了模型的一切,那么就没有理由访问飞船之外的模型。 Spaceship 可以加载模型,将其添加到场景中并完全处理它。我想这假设您在渲染循环中调用 spaceshipInstance.updatethe equivalent
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 2016-09-13
    • 2022-01-22
    • 2021-03-18
    • 1970-01-01
    相关资源
    最近更新 更多