Working with three.js: Implementing an external texture in a glTF file

In my quest to apply a texture file to a 3D model using three.js, I've hit a roadblock. Despite days of research and numerous attempts, I just can't seem to get it right. Here is the method I've been using to set the current object in the scene:

/**
 * SET method: Sets object in the scene (deleting previous one)
 * 
 * @author Anton Pernisch <<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="16777862797856667364787f65757e38727360">[email protected]</a>>
 * @param {string} modelPath - Path to object in glTF format
 * @param {string} texturePath - Path to texture
 * @returns {boolean}
 * 
 * @todo Texture
 */
SET_Object: function(modelPath, texturePath) {
    // Clear out the scene
    for (var i = this.prodconf3_scene.children.length - 1; i >= 0; i--) { 
        obj = this.prodconf3_scene.children[i];
        this.prodconf3_scene.remove(obj); 
    }

    const modelLoader = new THREE.GLTFLoader();

    modelLoader.load(modelPath, (gltf) => {
        // HERE? apply texture from texturePath to this gltf

        this.prodconf3_obj = gltf.scene;
        this.prodconf3_scene.add(this.prodconf3_obj);
    });
    
    return true;
}

The importation of the glTF works fine but the model appears black on the screen. After much trial and error, I managed to somewhat apply a .jpeg texture to the model resulting in this outcome: here.

My approach involved the following method:

/**
 * SET method: Sets current object to scene (deleting previous one)
 * 
 * @author Anton Pernisch <<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9bfaf5eff4f5dbebfee9f5f2e8f8f3b5fffed">[email protected]</a>>
 * @param {string} modelPath - Path to object in glTF format
 * @param {string} texturePath - Path to texture
 * @returns {boolean}
 * 
 * @todo Texture
 */
SET_Object: function(modelPath, texturePath) {
    // Clear out the scene
    for (var i = this.prodconf3_scene.children.length - 1; i >=0 ; i--) { 
        obj = this.prodconf3_scene.children[i];
        this.prodconf3_scene.remove(obj); 
    }

    const modelLoader = new THREE.GLTFLoader();
    const textureLoader = new THREE.TextureLoader();

    modelLoader.load(modelPath, (gltf) => {
        var model = gltf.scene;
        model.traverse((o) => {
            if (o.isMesh) {
                o.material = new THREE.MeshBasicMaterial({map: textureLoader.load(texturePath)});
            }
        });

        this.prodconf3_obj = model;
        this.prodconf3_scene.add(this.prodconf3_obj);
    });
    
    return true;
}

I also attempted to create a texture using the TextureLoader load method and then combine it with `gltf.scene` from the `modelLoader.load` function. However, this resulted in an error message:

Uncaught TypeError: Cannot read property 'center' of undefined

I'm unsure about using `gltf.scene` as the first argument in `THREE.Mesh()`.

Can anyone provide guidance on the correct and updated way to apply textures to glTF models in three.js?

Answer №1

Everything seems good to me, however, I can't help but wonder if we should be passing a reference to an already loaded texture.

Object3D#Traverse is not asynchronous, so we will need to update the material synchronously.

Check out the live example here.

SET_Object: async function(modelPath, texturePath) {
    // Clear the scene
    for (let i = this.prodconf3_scene.children.length - 1; i >= 0; i--) { 
        obj = this.prodconf3_scene.children[i];
        this.prodconf3_scene.remove(obj); 
    }

    const modelLoader = new THREE.GLTFLoader();
    const textureLoader = new THREE.TextureLoader();

    // Load texture
    const texture = await textureLoader.loadAsync(texturePath);
    texture.flipY = false;

    // Load model
    const { scene: model } = await modelLoader.loadAsync(modelPath);

    // Update model
    model.traverse((o) => {
        if (o.isMesh) {
            o.material.map = texture;
            o.material.needsUpdate = true;
        }
    });

    this.prodconf3_obj = model;
    this.prodconf3_scene.add(this.prodconf3_obj);
    
    return this.prodconf3_obj;
}

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

box tick does not alter appearance

I've been struggling with this seemingly simple issue for an hour now. I have a radio button set up with two buttons: <input class="form-control icheck" id="cash_prize" name="cash_prize" type="radio" value="1" style="position: absolute; opacity: 0 ...

When a URL is triggered via a browser notification in Angular 2, the target component ceases to function properly

Whenever I access a URL by clicking on a browser notification, the functionality of the page seems to stop working. To demonstrate this issue, I have a small project available here: https://github.com/bdwbdv/quickstart Expected behavior: after starting t ...

Issue with the Ajax auto-complete feature in Internet Explorer

I am facing an issue with my "ajax suggestion list" getting hidden behind the "select menu" located right below the text box that triggers the ajax function. This problem only occurs in IE 6.0, while it works fine in other browsers. I have already disabled ...

Modifying the image height in a column using Bootstrap and JSON data

My webpage is dynamically generating images from a JSON file through a JavaScript file. However, the images are displaying at different heights, and I want each column to adjust to the height of the image to eliminate any gaps. Particularly, data with the ...

ES6 Promises have a curious ability to accurately retrieve values from custom JavaScript objects

I have developed a unique library that functions independently from the Promise API, yet achieves similar objectives. It utilizes window.requestAnimationFrame and fallbacks to setTimeout, having no similarities with Promises. Interestingly, it is compatibl ...

Error in Node.js: [Error: Query parameter should not be empty]

I've been recently focusing on a project that involves sending the required name to my profile.js file using a POST request. However, whenever I try to access console.log(req.body.bookName) (as the data being sent is named bookName), it shows an error ...

Use the useEffect hook to pass newly updated data to a FlatList component

I have encountered an issue with updating a FlatList component in my React Native application. The scenario involves running a graphql query to render items and then refetching the data when a mutation is executed using Apollo's refetch option. Althou ...

Error in Mongodb: Unable to convert value into ObjectId

Currently, I am attempting to retrieve only the posts belonging to users using the following code snippet: router.get("/:username", async (req, res) => { try { const user = await User.findOne({ username: req.params.username }); const ...

Enhance multiple select functionality

I am currently working on a function to dynamically update the options in a select input based on the selection made in another select input. Specifically, when Method1 is selected, I want only the options 1A, 1B, and 1C to appear in the second select. S ...

HTML Date input field not respecting locale settings and defaults to mm/dd/yyyy format

When using an html date input in an ng-repeat scenario, I noticed that it defaults to mm/dd/yyyy even though my computer's regional settings are set to dd/mm/yyyy. <script src="//unpkg.com/angular/angular.js"></script> <body ng-app&g ...

Concealing HTML content with a modal overlay

There are security concerns with my authentication overlay modal, especially for users familiar with CSS and HTML. Is there a way to hide the HTML behind the modal so it doesn't appear in the page source? The code below is just an example of a modal ...

no visible text displayed within an input-label field

Currently, I have started working on a multi-step form that is designed to be very simple and clean. However, I am facing an issue where nothing is being displayed when I click on the next arrow. I am puzzled as to why it's not even displaying the te ...

Learn how to rearrange the order of Vue elements

I am working with a specific object structure in my code: lines: [{ order: '1', text: ' blue' },{ order: '2', text: 'green' },{ order: '3', text: 'yellow' }] Currently, thi ...

Tips for inserting a personalized image or icon into the ANTD Design menu

Can anyone help me figure out how to replace the default icons with a custom image or icon in this example: https://ant.design/components/layout/#components-layout-demo-side I attempted to do it by including the following code: <Menu.Item to="/" key=" ...

Updating columns in MongoDB using arrays in JavaScript has just gotten easier

When trying to update a mongoDB collection with an array value, the update fails without any error message. This method causes the issue: var arr = ["test","test1","test2"]; $.ajax('http://my.mongodb.com/collection?id=80a2c727de877ac9' , { ...

Accessing a Child Component Function in Material UI

Utilizing the Material UI framework, I am constructing an application with React. Included in this application is a Dialog feature that permits users to modify various information about an object (referencing the code below). The dialog consists of two but ...

What is the best way to include the existing query string value in the hyperlinks on my page?

My main coding objective is to simultaneously search multiple websites. To accomplish this, I want to create a query string containing the search terms (primarily for analytics purposes) using a form. By utilizing JavaScript, I am aiming to include the s ...

Unable to process despite clicking button (no error messages)

I'm in the process of setting up an options page for my very first extension. As a beginner in coding, I might have made some rookie mistakes along the way. However, I am facing challenges with basic functionality that was previously working seamlessl ...

JavaScript Cookie to Ensure Form Submission is Limited to a Single Instance

Seeking assistance with automatically submitting a form on page load using JS cookies. Here is the code I have, but it's not functioning as expected. Any guidance would be greatly appreciated. Thank you. I'm unsure about the section in my code th ...

Change from using fs.writeFileSync to fs.writeFile

I have a question about changing fs.writeFileSync to fs.writeFile const users = { "(user id)": { "balance": 28, "lastClaim": 1612012406047, "lastWork": 1612013463181, "workersCount": 1, ...