Guide on loading '.obj' files with multiple '.mtl' files using Three.js

I am attempting to load the cube.obj file which references multiple cube_*.mtl files, each of which utilize texture images in the format *.png. The resources can be found here. My goal is to dynamically load objects with the same geometry but different materials by loading multiple mtl files.

After researching, I attempted to combine examples from the no longer supported MultiMaterial documentation, and the webgl_loader_obj_mtl example. This involved loading all mtl files, creating a MultiMaterial, and then loading the obj file:

var resources = 'cube/';
var materialsToLoad = [
    'cube_red.mtl',
    'cube_green.mtl',
    'cube_blue.mtl'
];

var loadedMaterials = [];

var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath(resources);
for (var i = 0; i < materialsToLoad.length; i++) {
    mtlLoader.load(materialsToLoad[i], function(materials) {
        materials.preload();
        loadedMaterials.push(materials);
    }); 
}

var multi = new THREE.MultiMaterial(loadedMaterials);
var objLoader = new THREE.OBJLoader();
objLoader.setPath(resources);
objLoader.setMaterials(multi); // #1
objLoader.load('cube.obj', function (object) {
    scene.add(object);
});

However, this approach resulted in an exception being thrown:

Uncaught TypeError: this.materials.create is not a function
at THREE.OBJLoader.parse (OBJLoader.js:684)
at OBJLoader.js:50
at XMLHttpRequest.<anonymous> (three.min.js:619)

I am seeking guidance on what I might be doing wrong and how to properly achieve my goal.

Answer №1

It seems like there are a few issues to address in this situation.

1) The behavior of THREE.MTLLoader.load is causing a delay in loading OBJ files as it operates as a "non-blocking" function. To resolve this, ensure that the OBJ files are loaded within the callback function provided in mtlLoader.load(). Refer to the example mentioned for clarification.

2) When using the mtlLoader.load callback function, keep in mind that the argument 'materials' is of type THREE.MTLLoader.MaterialCreator. Therefore, loadedMaterials should be an array of THREE.Material elements to create a THREE.MultiMaterial (no longer supported by three.js). Additionally, MultiMaterial is intended for assigning multiple materials to individual object faces, not for selecting a material at your discretion.


To tackle this issue (code has not been tested), follow these steps:

Start by creating a LoadingManager:

var manager = new THREE.LoadingManager();

This will ensure all MTL files are loaded before proceeding with OBJ loading:

manager.onLoad = function() {
    /* 
       All MTL files have been loaded.
       We can now load an OBJ using the first available material option.
    */

    if (loadedMaterials.length > 0) {
        var objLoader = new THREE.OBJLoader();
        objLoader.setPath(resources);
        objLoader.setMaterials(loadedMaterials[0]); // First material
        objLoader.load('cube.obj', function (object) {
            scene.add(object);
        });
    }
};

Next, load all MTL files:

var mtlLoader = new THREE.MTLLoader(manager);
mtlLoader.setPath(resources);
for (var i = 0; i < materialsToLoad.length; i++) {
    mtlLoader.load(materialsToLoad[i], function(materials) {
        materials.preload();
        loadedMaterials.push(materials);
    }); 
}

Hopefully, these suggestions prove helpful!

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

Disable ESLint's "no-undef" rule for a specific folder when using Jest

Currently, I am using jest for testing my api calls. In addition, I utilize eslint to validate my test codes. However, since jest does not require explicit definition of methods such as test() or expect(), when running eslint, I encounter errors like: ...

Converting a Perl hash into a JavaScript hash: A comprehensive guide

I am currently using the template toolkit framework and working with a Perl hash data type in my tt file. My goal is to convert this Perl hash data type into a JavaScript hash data type. Code: template: [% PERL %] use JSON qw(encode_json) ...

Creating a form in PHP with the power of JavaScript, AJAX, and jQuery

I have successfully created a registration form using HTML, processed the data with PHP, and utilized javascript, ajax, and jquery. However, I am facing an issue where I want to display a notification stating whether the operation was "inserted/failed" on ...

Is there a way to determine the number of syllables in text as it is being typed?

Working on a React-based web app, I am trying to determine the number of syllables in a textarea as the user types. Encountering errors like "cannot find length of a null" at every turn. Right now, all I want is to utilize console.log() for troubleshooti ...

Error: An unexpected TypeError occurred while attempting to fetch an array or collection from MongoDB Atlas

As a beginner in the world of Express and Mongoose, I am currently working on retrieving an object from MongoDB Atlas using Mongoose.Model for educational purposes. In CoursesModel.js, I have defined the schema for my collections and attempted to fetch it ...

What could be causing the issue with dayjs dynamic importing in TypeScript?

Currently, I am developing a web screen within a .NET application and facing an issue with sending datetime preferences from the system to the web screen using CefSharp settings. AcceptLanguageList = CultureInfo.CurrentUICulture.Name In my TypeScript code ...

Keycloak does not support using the updateToken() function within an asynchronous function

In our development of a Spring application with React/Redux frontend, we faced an issue with Keycloak authentication service. The problem arose when the access token expired and caused unexpected behavior in our restMiddleware setup. Here is a simplified v ...

Is there a way to execute "npm run dev" within cPanel while I am currently working on a Laravel project?

Currently, I am working on a Laravel project and require to execute the following command in Cpanel terminal: npm run dev https://i.sstatic.net/bzxNj.png ...

Unable to start initial Cucumber+javascript demonstration

I attempted to run the initial example provided in the official documentation found here. Using Windows 7x64 bit and node.js version 6.11 I ran the following commands but encountered the same outcome. * node_modules/cucumber/bin/cucumber.js autotests/c ...

Dropdown selection not getting updated when modifying DropdownSection component

My Link dropdown triggers a DropdownSection component that includes an array of options. If I switch to a different Link, I want the default option in the DropdownSection to be set to the second option from the linkOptions array, skipping the initial "No ...

Simple steps for importing JS files in a web application

Upon examining the code snippet below: const express = require('express'); const app = express(); const http = require('http').Server(app); const io = require('socket.io')(http); const cors = require('cors'); app.u ...

"Encountering an error in Vue.js when trying to dynamically access nested arrays: push function not

My goal is to have two buttons displayed when a user uploads data: one for old products and one for new products. When the user clicks on either button, the corresponding products will be uploaded as 'old_product' or 'new_product'. Howe ...

Learn how to find and filter elements in arrays that do not include a particular value using React

In my collection of recipes, I have the ability to filter out the ones that include specific ingredients. However, when I attempt to reverse this process by using .some method, it only checks the first item in the array. Here is an example of my data stru ...

Create a feature that allows users to view photos similar to the way it

I want to incorporate a Twitter feed on my website that displays images posted. Instead of having the images redirecting users to Twitter when clicked, I would like them to reveal themselves underneath when a link labeled "View Photo" is clicked, and then ...

Guide to sequentially playing multiple video objects with buffering

As I work on developing a reference player application that utilizes node.js, javascript, and HTML5, I have encountered an issue. Currently, my player successfully loads a single video and generates diagnostic data from it. However, I am striving to enhanc ...

Omitted Script within a Node.js JavaScript Code Segment

My code snippet is: function write_to_orchestrate(data_to_write) { console.log('more testing'); db.put('musician', '1', '{"test":"test1"}') .then(function (result) { res.send(result); ...

"Optimizing reload time for DIV content with jQuery's .load function is proving to be

I am currently facing an issue with a div that displays data from a database and a form that updates item quantities. After submitting the form, the div refreshes while a modal with a bootstrap spinner pops up to indicate it is loading. The problem arises ...

Disable the enter key from closing the alert box

Is there a way to ensure that a user must manually close a JavaScript alert, preventing them from simply closing it by pressing enter? (It may sound suspicious, but in the application users frequently press enter and I need to make sure they don't ov ...

Looking to showcase a loading gif inside a popover before swapping it out with ajax-generated content

My goal is to populate a popover with content using ajax requests. Here's the setup: $('.openMessagePopover').popover({ html: true, content: function() { $threadId = $(this).data('id'); return getContent($threadId) ...

Reveal each element individually upon clicking the button

I am trying to display 5 div elements one by one when clicking a button, but the current code is not working. I am open to alternative solutions for achieving this. Additionally, I want to change the display property from none to flex in my div element. ...