Using Three.js to Apply Various Materials to an Imported OBJ Model

After creating an OBJ file using Blender with two materials assigned, I successfully imported the file.

Now, my question is: How can I assign different materials to the faces in Three.js? I believe the materials need to be included in an array, but I'm unsure if I did it correctly. I want to assign the materials to the faces.

This snippet shows the relevant part of my code:

....

  loader.load( './beardedbox3.obj', addBananaInScene);
};

var addBananaInScene = function(object){

  banana = object;
  // Moving the banana in the scene
  banana.rotation.x = Math.PI/2;
  banana.position.x = 0;
  banana.position.y = 0;
  banana.position.z = 0;
  banana.scale.x = 200;
  banana.scale.y = 200;
  banana.scale.z = 200;
   
  var white = new THREE.MeshPhongMaterial( { color: 0xffffff, 
                                        specular: 0xffffff, 
                                        shininess: 30, 
                                        shading: THREE.FlatShading } );
  var red = new THREE.MeshPhongMaterial( { color: 0xff0000, 
                                        specular: 0xFF9900, 
                                        shininess: 30, 
                                        shading: THREE.FlatShading } ); 

  object.traverse( function ( child ) {
    if(child instanceof THREE.Mesh){
        child.materials = [white, red];
        child.geometry.computeVertexNormals();
    }
  });

  // Adding the 3D object to the scene
  scene.add(banana);

The structure of the OBJ file is as follows:

.... Vertex coordinates
usemtl white
s 1
f 1//1 2//1 3//1
f 4//2 5//2 6//2
... more faces
f 130//23 34//23 141//23
usemtl red
f 41//51 42//51 43//51
f 45//52 46//52 47//52
f 42//53 11//53
... additional faces

This appears to be a situation where a loop can be utilized to assign materials to faces. However, I am uncertain about how to proceed. Is there a simpler way?

Regards, Christian

Edit:

Thank you for your response. Your explanation makes sense, but I am struggling to make it work. It seems like there is a gap in my basic knowledge.

The key part of my updated code is as follows:

var white = new THREE.MeshPhongMaterial({
  color: 0xffffff,
  specular: 0xffffff,
  shininess: 30,
  shading: THREE.FlatShading
});

var red = new THREE.MeshPhongMaterial({
  color: 0xff0000,
  specular: 0xFF9900,
  shininess: 30,
  shading: THREE.FlatShading
});

object.traverse(function (child) {
  if (child instanceof THREE.Mesh) {
    child.materials = [white, red];
    child.geometry.computeVertexNormals();
    child.geometry.elementsNeedUpdate = true;

    for (var i = 0; i < child.geometry.faces.length; i++) {
      if (i < child.geometry.faces.length / 2) {
        child.geometry.faces[i].materialIndex = 0;
      } else {
        child.geometry.faces[i].materialIndex = 1;
      }
    }
  }
});

However, I encountered the following error message:

TypeError: child.geometry.faces is undefined
    addBananaInScene/<()                   box.js:78
    THREE.Object3D.prototype.traverse()    three.min.js:179
    THREE.Object3D.prototype.traverse()    three.min.js:179
    addBananaInScene()                     box.js:69
    THREE.OBJLoader.prototype.load/<()     OBJLoader.js:25
    THREE.XHRLoader.prototype.load/<()     three.min.js:377

It seems like I made a mistake somewhere. Any help would be greatly appreciated.

Christian

Answer №1

A great solution is to implement multimaterial.

You can assign different materials to different faces of your geometry by using multimaterial. After loading the obj file, you have the flexibility to assign specific materials to specific parts of your model. For example, you can set the first half of faces to use one material and the remaining faces to use another:

for (var i = 0; i < geometry.faces.length; i++) {
  if (i < geometry.faces.length / 2) {
    geometry.faces[i].materialIndex = 0;
  } else {
    geometry.faces[i].materialIndex = 1;
  }
}

Answer №2

To include various materials within a single object, you can utilize the following code snippet:

var loader = new THREE.OBJLoader( manager );
loader.load( 'obj_model/Jersey_1.obj', function ( event ) {
var object = event;
var geometry = object.children[ 0 ].geometry;
var materials = [];
materials.push(new THREE.MeshLambertMaterial( { map : THREE.ImageUtils.loadTexture( 'obj_model/Jrsy_1_Color_1.png'),transparent: true, opacity: 1,color: 0xFF4C33 } ) );
materials.push(new THREE.MeshLambertMaterial( { map : THREE.ImageUtils.loadTexture( 'obj_model/Jrsy_1_Color_2.png'),transparent: true, opacity: 1,color: 0xFFF933 } ) );
materials.push(new THREE.MeshLambertMaterial( { map : THREE.ImageUtils.loadTexture( 'obj_model/Jrsy_1_Tag.png'),transparent: true, opacity: 1,color: 0xFF0000 } ) );
materials.push(new THREE.MeshLambertMaterial( { map : THREE.ImageUtils.loadTexture( 'obj_model/Jrsy_Ptrn.png'),transparent: true, opacity: 1,color: 0xFF33E0 } ) );
mesh = THREE.SceneUtils.createMultiMaterialObject(geometry, materials);
mesh.scale = new THREE.Vector3( 8,8,8 );
scene.add(mesh);
});

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

The simultaneous use of trackball controls and GUI is not compatible

When I click on them, the GUI changes together and I have looked at other answers. However, I am not sure where to put the listener. I tried putting the listener in render(), but it still doesn't work. How can I fix my code? This coding is related to ...

Creating an Organized Framework for a Website Application

In my particular case, I am utilizing an AngularJS application, although I believe this inquiry is relevant to any Single Page App. I've implemented a component structure as outlined in various resources such as this and this. Let's assume I ha ...

Tips for improving the performance of the JavaScript code mentioned

Can you assist with optimizing the code below? The question at hand is whether all values in this array need to be checked to see if two of them sum up to 8. If yes, then we should identify the indexes of these values. const arr = [1, 2, 3, 4, 5]; const ...

When properties are passed and then mapped, they become undefined

While I experience no errors when directly mapping the array, passing the same array through props results in an error stating "Cannot read property 'map' of undefined." Brands Array const brands = [ { key: 1, Name: "Nike", }, { ...

Issue with express-validator returning undefined value on forms set to enctype='multipart/form-data'

Currently, I am developing a login authentication application using basic node.js+express. While extracting values (such as name, email, etc) from the registration page, I utilize express-validator for validation. However, I encounter an issue where all va ...

SignalR 2.2 application encountering communication issues with client message reception

I am facing an issue in my application where clients are not receiving messages from the Hub when a user signs in. Here is my Hub class: public class GameHub : Hub { public async Task UserLoggedIn(string userName) { aw ...

Utilizing GroupBy in RxJs for an Observable of Objects数组

I am working with entries of type Observable<Event[]>, and they are structured as follows: [{ "_id": 1, "_title": "Test Event 1", "_startDate": "2019-05-29T07:20:00.000Z", "_endDate": "2019-05-29T08:00:00.000Z", "_isAllDay": false }, ...

Is there a conflict between bootstrap.min.JS and chart.min.js?

I have been working on developing an admin page for customer support and I recently added a visually appealing chart to display some data on the home screen. The chart integration was successful, but when I introduced tab panes to the page and refreshed ...

Strategies for tracking distinct property values in Firestore

Is it possible to count the occurrences of unique values in Firestore? For instance, if there are 1000 documents with dates and only 50 different dates repeated, how can I get a list of each date along with its frequency? Context: These documents represe ...

Error: Encountered an unexpected token while trying to parse multiple form functions

I recently added the following submission function to my .js file: $( "form" ).on( "submit", function( event ) { event.preventDefault(); var data = $( this ).serialize(); $.ajax({ type: "POST", url: "content/rev/a_sub ...

Concerns about the Dependency Tree in React

I need some assistance with my current issue. I'm having trouble installing the mui search bar component. npm i --save material-ui-search-bar Unfortunately, I'm encountering this error message: PS Z:\WebDev\ApplyWithin\frontend> ...

Maintain cookie persistence beyond browser shutdown

Using this code snippet in Node-Express JS, I am creating a cookie with a JWT token included. Here is the code: var token = jwt.sign(parsed.data, "token_secret", {expiresIn: "43200m"}); res.setHeader('Set-Cookie', 'token='+token+&apos ...

The animation is not updating quickly enough

I'm working on a navigation bar that sticks to the top of the page. As the user scrolls down, I want the bar to shrink, and when they scroll back up, it should return to its original size. Issue: The problem I'm facing is that when the user quic ...

What is the best way to extract a specific year and month from a date in a datatable using

My dataset includes performance scores of employees across various construction sites. For instance, on 2020-03-15, ALI TAHIRI was at the IHJAMN site. I need to filter this dataset by year and month. If I input 2020 for the year and 03 for the month, the d ...

What could possibly be causing my MongoDB collection to return an empty object?

I've been attempting to retrieve all the data from my "users" collection, but all I keep getting is undefined. Within my directory and file labeled leaderboard/lb.js, and indeed, my database goes by the name of collections: const mongoose = require( ...

Best resolutions and formats for Nativescript-Vue application icons

I'm a newbie when it comes to Nativescript, and I'm looking to change the icon for my app. After doing some research, I found this command: tns resources generate splashes <path to image> [--background <color>] This command seems li ...

Convert your Node.js server URL hosted on AWS Elastic Beanstalk to HTTPS

Struggling to deploy my React JS app using AWS S3 bucket as I am new to the platform. The app communicates with a Node/Express server hosted on an Elastic Beanstalk environment. Encountered the error: Mixed Content: The page at 'https://myReactApp.s3. ...

Navigate to the specified URL once the Ajax function has completed successfully

I'm having trouble with opening a URL from an Ajax function. It seems like the URL is not being called. This is the code I am using: $(document).on( "click",".btndriver", function() { var id = $(this).attr("id"); var nombre = $(this).att ...

The annoying Facebook "add a comment" popup refuses to close

Occasionally, the "add a comment" popup (iframe) in Facebook's Like plug-in fails to close and obstructs access to the content underneath. This issue has been noted while using Chrome 21 and Firefox 15. To replicate this problem, you can visit the fo ...

Utilizing jQuery to add elements to a webpage

I need to populate an empty div on my webpage using jQuery. Here's an example: <div class="content"> </div> After the first insertion, I want the markup to look like this: <div class="content"> <div class="inserted first"& ...