What are some ways to ensure that my gltf loader in three.js operates synchronously?

I have a question regarding my code. I'm currently working on making the loadCone() function synchronous using async/await, but I'm facing some issues with it.

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

In another file, I am trying to add the cone like this:

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

The issue I'm facing is that because getCone() is synchronous, it gets executed before loadCone() finishes loading the cone, resulting in getting undefined instead of the actual cone object.

Any suggestions on how I can make my async loadCone() function synchronous? I've tried using *.loadAsync()` but it didn't yield any different results.

Thank you in advance. So far, I haven't encountered any errors, except for the expected message saying "undefined is not an instance of THREE.Object3D".

Answer №1

Although I am not familiar with three.js, it is important to note that the new keyword must synchronously return an initialized object, making it impossible to be asynchronous.

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

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

    // avoid calling async methods here
    // this.loadCone();
}
//...

When calling the method...

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

If we notice that loadCone mixes promises and callbacks, we can either promisify the current version used or consider @Leon.Z's suggestion regarding the promise-returning version for simplicy of the cone class like so...

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() {
        if (this.cone) Promise.resolve(this.cone);
        const gltf = await gltfLoader.loadAsync( 'model.gltf' ),
        this.cone = gilt.scene;
        return this.cone;
    }
    
    getCone() { return this.cone; }
}

In case @Leon.Z is mistaken about the promise method, below is how you can promisify the loader...

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

Answer №2

I'm a bit confused about what you're trying to achieve.

This is how I've been able to make it work:

  // Loading a glTF file
  async loadGltfFile(url) {
    // console.log('===== start loadGltfFile async')
    let urlString = url.toString()  // The loading process requires a string URL format, so we convert it first
    let gltf = await gltfLoader.loadAsync(urlString)
    // console.log('========== end loadGltfFile')
    return gltf
  }

To access the scene in the result, use result.scene

Answer №3

According to the official documentation, you can utilize the loadAsync method provided by threejs loaders in the following manner.

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to invoke a controller function from a window listener function

Is there a way to trigger the close function from window.onbeforeunload even when closing the app through 'right click' -> 'close window'? It seems that this.close() is not working in this scenario, possibly due to scope issues. The ...

Tips for declaring a non-reactive instance property in Vue.js with TypeScript

I am currently in the process of transitioning my Vue.js components to TypeScript. In accordance with the recommendations provided in the documentation, I attempted to utilize Vue.extend() for my component implementation. The code snippet for my component ...

Issue with jQuery animation delay functionality experiencing issues specifically in Google Chrome browser

While browsing through similar questions, I couldn't find one quite like mine where the effect was working on one window but not on a subsequent one. I'm using jQuery library version 3.4.1. The code has been tested and is functioning as expected ...

Deploying an Angular 2 application using SystemJS and Gulp can sometimes feel cumbersome due to its

Although I have experience developing with Angular, I recently started working with Angular 2. After completing the quickstarter tutorial, I attempted to deploy the finished application on a server in production mode. My lack of experience with SystemJS a ...

Issue encountered: Trying to deploy firebase functions and hosting with vue-cli v3 and node.js leads to an error "No npm package found in functions source directory

My plan is to utilize Vue.js for the Frontend and Firebase Functions (Express.js) + Firestore for the Backend. Step 0: I initiated a new project on Google Firebase, then created a new Service Account with Owner's permissions to be used with Admin SDK ...

Locating specific text within an <li> element using the provided value

So, I have this set of words: <li>name</li> <li>myname</li> <li>yourname</li> Then there's also an input box input type="text" value="name" id="the_value" with the value "name", along with a submit button identif ...

When the clearInterval function is invoked - either when the timer is modified or when the rendering is detached from the setInterval it is linked to

As a new React developer, I've come across a problem that has me stuck. Does the setInterval associated with a specific render get cleared automatically? import React, { useState, useEffect, useRef } from "react"; import ReactDOM from ...

Discover the secrets to easily finding specific items within a table by harnessing the power of the table sorter plugin with

Currently, I am utilizing the tablesorter plugin and its corresponding tablesorter widgets to facilitate searching within a table. However, I encountered an issue with the tablesorterWidgets.js file when attempting to configure the number of rows displayed ...

FireFox 3.0.1: Failure to Modify Width and Height Using jQuery

Currently, I am utilizing the jQuery user interface to adjust the size of a DIV element and also resize the embedded YouTube video within it. For more information, you can visit this link. When the main DIV is resized, the YouTube video should automatica ...

Retrieve all files from a directory that include a specific string, store the file names in an array, and then return the array using

Exploring a new challenge, I am attempting to scan a specific directory for files that contain a particular string in their contents and compile a list of their names. Here is the code snippet I have developed up to this point: const dirname = path.res ...

In my efforts, I am attempting to retrieve a value using JavaScript in order to send it back to PHP in JSON format

I have successfully developed a date selection feature with the chosen date displayed at the bottom (Second box in green). Now, I am looking to extract the user's selection in PHP and then send it in JSON format. Any suggestions or assistance on this ...

Modify: "Alter the background color of the parent container for elements that are deemed invalid during

I am currently working on implementing asp.net's built-in validation feature to indicate required fields, but I want to take it a step further by not only displaying a message but also changing the background color of the parent div containing the inv ...

Automatically reveal or conceal an element based on the entry of a value in an input field, without relying on the keyup() or click events

I have a form field with a Bootstrap Datepicker that populates an <input> tag with a selected date. <div class="wrapper"> <div class="form-group"> <label>Select Date</label> <div class="input-group"> ...

Dependable Timeout Functionality in JavaScript

We are currently developing an AngularJS application that presents users with questions and keeps track of the number of correct answers within a strict 20-minute time limit. However, there are some challenging requirements we need to consider: Accuracy C ...

CSS class for Angular drag-and-drop functionality during drag operation

I have implemented the Angular dragdrop functionality in my application. Currently, I am looking to modify the border color of the drop area when an item is being dragged over it. Is there a specific CSS class that I can utilize for achieving this? If no ...

I seem to be struggling with hiding/showing a div element. Can you figure

I am in the process of creating a gallery that will display a div with images when a button is clicked. The issue I am facing is that when I have two buttons, only the last images are clickable. It's a bit difficult to explain, but you can see it in ...

Alter the class when $dirty occurs in Angular

I've recently started working with angular js and am attempting to incorporate animations into my login page. I have created a controller that will modify the class of the input field when clicked and when blurred. app.controller("con", function($sc ...

Top Margin: Supported by Chrome and Safari

After troubleshooting why the margin-top is not working on Safari, but works fine on Chrome, I discovered a discrepancy. Chrome Upon hovering over an item in the image, the cursor changes as expected. This feature operates smoothly in Chrome. https://i. ...

Obtain the complete source code by using the responseText property of the XMLHttpRequest object

I am looking to retrieve the entire source code of a webpage, such as www.google.com. Currently, I have a PHP file that can copy the source code of a page: <?php echo file_get_contents('http://www.google.com'); ?> Here is my function ...

What is the best way to export a React Material-UI component with two separate styles objects in Material-UI V1?

We are currently utilizing material-ui version 1 and composing Higher Order Components (HOC) with the recompose utility. Our issue arises from having two separate styles objects - one defined within the component itself, and another general style object th ...