如何让我的 gltf 加载程序在 three.js 中同步?

How do I make my gltf loader synchronous in three.js?

这是我的代码,我试图使 loadCone() 与 await/async 同步,但它不起作用。

import * as THREE from "three";

import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

import conePath from "../../static/cone.glb";
import coneBaked from "../../static/coneBake.png";

import "regenerator-runtime/runtime";

export default class Cone {
    constructor() {
        this.cone;
        const textureLoader = new THREE.TextureLoader();

        const bakedTexture = textureLoader.load(coneBaked);
        const bakedMaterial = new THREE.MeshBasicMaterial({
            map: bakedTexture,
        });

        this.loadCone();
    }

    async loadCone() {
        // GLTF loader
        const gltfLoader = new GLTFLoader();
        const cone = await gltfLoader.load(
            conePath,
            (gltf) => {
                console.log("success");
                console.log(gltf.scene);
                this.cone = gltf.scene;
            },
            (progress) => {
                // console.log("progress");
                // console.log(progress);
            },
            (error) => {
                console.log("error");
                console.log(error);
            }
        );
    }

    getCone() {
        return this.cone;
    }
}

在另一个文件中我有这个:

const cone = new Cone();
this.scene.add(cone.getCone());

但是,因为 getCone() 是同步的,它会在我的 loadCone() 加载圆锥之前执行,所以我得到 undefined 而不是圆锥。

如何使我的函数 asynch loadCone() 同步?我试过 *.loadAsync()` 但它没有改变任何东西。

提前致谢。我没有收到任何错误,除了它说“undefined is not instance of THREE.Object.3d”,我希望它说的。

根据文档,有一个来自 threejs 加载器的 loadAsync 方法,您可以按如下方式使用。

await gltfLoader.loadAsync( 'model.gltf' ),

我不太明白你在做什么。

我用这个成功了:

  // Load a glTF resource
  async loadGltf(url) {
    // console.log('===== start loadGltf async')
    let urlString = url.toString()  // load doesn't like the url structure; it requires a string and then builds it up again
    let gltf = await gltfLoader.loadAsync(urlString)
    // console.log('========== end loadGltf')
    return gltf
  }

根据结果,访问result.scene

我不知道 three.js,但是 new 需要同步 return 一个初始化对象,所以它不能(或调用其他东西)异步。

// ...
constructor() {
    this.cone;
    const textureLoader = new THREE.TextureLoader();

    const bakedTexture = textureLoader.load(coneBaked);
    const bakedMaterial = new THREE.MeshBasicMaterial({
        map: bakedTexture,
    });

    // don't call an async method here
    // this.loadCone();
}
//...

在来电方...

import Cone from 'path to js that defines the class'

// inside an async function
async function doConeStuff() {
  const cone = new Cone();
  await cone.loadCone();
  this.scene.add(cone.getCone());
}

// or, at the top level
const cone = new Cone();
cone.loadCone().then(() => {
  this.scene.add(cone.getCone())
});

注意到 loadCone 混淆了承诺和回调,我们可以承诺您正在使用的版本,或者采纳@Leon.Z 关于 promise-returning 版本的建议。如果那个有效(同样,我不知道 three.js),那么圆锥体 class 可以像这样简化...

export default class Cone {
    constructor() {
        const textureLoader = new THREE.TextureLoader();

        const bakedTexture = textureLoader.load(coneBaked);
        const bakedMaterial = new THREE.MeshBasicMaterial({
            map: bakedTexture,
        });
        this.cone = null;
    }

    async loadCone() {
        // GLTF loader
        if (this.cone) Promise.resolve(this.cone);
        const giltf = await gltfLoader.loadAsync( 'model.gltf' ),
        this.cone = gilt.scene;
        return this.cone;
    }
    
    getCone() { return this.cone; }
}

最后,如果由于某种原因,@Leon.Z 对 promise 方法不正确,请按以下方式对加载程序进行 promise...

async loadCone() {
  const gltfLoader = new GLTFLoader();
  return new Promise((resolve, reject) => {
    gltfLoader.load(
      conePath,
      gltf => resolve(gilt.scene),
      error => reject(error)
    );
  });
}