Utilizing Three.js to apply various materials on an object loaded through OBJMTLLoader

I have two files, an ".obj" and a ".mtl", of a model that I am loading using the OBJMTLLoader. The ".mtl" file specifies the texture to be applied to the model, and three.js successfully loads and renders the model with the applied texture.

However, I want to apply another texture onto the already loaded object. The first texture represents the surface material of the object, while the second texture is a drawing that I want to position at a specific location on the model.

So, my question is: how can I apply a second texture onto an already loaded and textured object?

I noticed that three.js creates an instance of THREE.Object3D, which has a "children" array containing one instance of THREE.Mesh.

When I try to apply a texture to this mesh (mesh.material.map = texture), the initial texture is lost.

I checked out a similar question regarding multiple textures and JSONLoader, but did not find a suitable answer.

I also attempted to use

new THREE.MeshFaceMaterial( materials )
as recommended in another answer without success.

UPDATE:

Despite following @WestLangley's advice to utilize a multi-material object, I am still unable to render one material on top of another.

In my simple demo derived from three.js OBJLoader, I used this link as reference. I employed

THREE.SceneUtils.createMultiMaterialObject
by passing it the cloned geometry of the main mesh loaded from .obj along with two textures - one for the entire surface and another for the front surface of the model.

Unfortunately, this approach didn't yield the desired outcome. Even after adding checkboxes to toggle the visibility of corresponding materials, it was evident that both materials were present, yet I couldn't see the first one beneath the second.

The key aspects of the loading/rendering process are summarized below:

var texture = THREE.ImageUtils.loadTexture('fabric.jpg');
var texture2 = THREE.ImageUtils.loadTexture('table.jpg');

texture2.offset.set(-0.65, -2.5);
texture2.repeat.set(4, 4);

var loader = new THREE.OBJLoader();
loader.addEventListener( 'load', function ( event ) {

  var mainMesh = event.content.children[0].children[0];

  multiMaterialObject = THREE.SceneUtils.createMultiMaterialObject( 
    mainMesh.geometry.clone(), [
      new THREE.MeshLambertMaterial({ map: texture2 }),
      new THREE.MeshLambertMaterial({ map: texture })
    ]);

  multiMaterialObject.position.y = -80;
  scene.add(multiMaterialObject);
});

loader.load( 'male02.obj' );

UPDATE #2

At this stage, I am considering utilizing THREE.ShaderMaterial to apply one texture over another. Though there are some examples demonstrating the usage of a single texture, I remain uncertain about how to display both in an overlaid state and how to precisely position the texture on a mesh.

Answer №1

When it comes to combining images in web development, you have a few options:

  1. One approach is to mix the images using canvas tools in JavaScript and create a single material with a unified texture map.

  2. Another option is to achieve a multi-texture effect by utilizing a custom ShaderMaterial. This involves having two texture inputs and implementing color mixing directly within the shader code.

If you're interested in seeing an example of a basic three.js ShaderMaterial that demonstrates how to blend two textures together, check out this JSFiddle link: https://jsfiddle.net/fvb85z92/.

This code snippet is compatible with three.js version r.150.

Answer №2

The object you've loaded contains geometry data like vertices, faces, and UV coordinates, as well as material information. To create a ShaderMaterial, combine the textures in a way that works for you and apply it to the mesh using the geometry from the loaded object.

Utilize ShaderMaterial by setting both textures as uniforms and blending them within the shader code.

Start by defining your ShaderMaterial:

var vertShader = document.getElementById('vertex_shh').innerHTML;
var fragShader = document.getElementById('fragment_shh').innerHTML;

var attributes = {}; // custom attributes

var uniforms = {  
  tOne: { type: "t", value: THREE.ImageUtils.loadTexture("cover.png") },
  tSec: { type: "t", value: THREE.ImageUtils.loadTexture("grass.jpg") }
};

var material_shh = new THREE.ShaderMaterial({
  uniforms: uniforms,
  attributes: attributes,
  vertexShader: vertShader,
  fragmentShader: fragShader
});

Then, apply this material to the mesh:

var mesh = new THREE.Mesh(my_loaded_model, material_shh); // Load the object's geometry beforehand

You can use a simple vertex shader:

varying vec2 vUv;

void main() {
    vUv = uv;
    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
    gl_Position = projectionMatrix * mvPosition;
}

As for the fragment shader responsible for blending:

#ifdef GL_ES
precision highp float;
#endif

uniform sampler2D tOne;
uniform sampler2D tSec;

varying vec2 vUv;

void main(void) {
    vec3 color;
    vec4 texA = texture2D(tOne, vUv);
    vec4 texB = texture2D(tSec, vUv);
    color = texA.rgb * texA.a + texB.rgb * texB.a * (1.0 - texA.a);
    gl_FragColor = vec4(color, 1.0);
}

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

Storing various text inputs in a MySQL database

Could anyone please assist me with fixing an issue I'm having with inserting data into a database from the form provided below? Unfortunately, I am unable to get it to work as expected. Here is the complete form: <html> <head> <m ...

What other methods are available to verify null and assign a value?

Is there a more efficient approach for accomplishing this task? theTitle = responsesToUse[i]["Title"]; if(theTitle == null) theTitle = ""; ...

Update of input not available

Does anyone know how to effectively transfer data from one page to another programmatically? I'm facing an issue where updating an input field doesn't work unless I manually edit it afterwards. Is there a better way to achieve this? Another prob ...

Utilizing ReactJs to Efficiently Parse JSON Data from API Requests

I am facing an issue with my React form where I need to pre-fill multiple fields using data retrieved from an async json call. Despite trying to set the button values based on attributes from the main json, the data is not available after loading. How can ...

What is the best way to link three asynchronous calls together using jQuery promises?

Is it possible to make three HTTP calls synchronously and pass data from one call to the other? function first() { ajax() } function second() { ajax() } function third() { ajax() } function main() { first().then(second).then(third) } I a ...

What causes the error "Why am I receiving a "Cannot read property 'length' of undefined" when looping through a pug template?

Currently, I am in the process of developing a project using Node and Express. My objective is to have the home page display signup and login links in the nav bar when the user is not logged in. Initially, everything seemed to be working fine, and I was ab ...

What is the process for extracting HTML content using the JavaScript executor?

import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; public class WebDriverExample { public static void main(String[] args) { System.setProperty("webdriver.c ...

JavaScript list items experience unreliability once stored in the database

I am in the process of setting up an ajax endpoint on my server to create a new transaction object and add it to a block, which is then added to a local blockchain. The problem arises when I invoke my database function add_block, responsible for adding th ...

Disabling the ability to select Saturday and Sunday within the Ionic calendar application

I came across a tutorial online at "" that explains how to create an event calendar in Ionic. I followed the tutorial and successfully implemented it, but I now have a specific issue. I want to make Saturdays and Sundays unselectable, meaning users should ...

Setting up Node.js for production on Nginx: A comprehensive guide

I am working on developing a chat system using angularjs and nodejs. To enable message sending and receiving, I have implemented socket.io. Initially, I set up a node.js server using localhost cmd. Everything is functioning properly, but now I need to dep ...

Issues with react-bootstrap component Switches functionality not operating as expected

It looks like the bootstrap switches are not functioning properly. Even the documentation version is not working as expected <Form> <Form.Check type="switch" id="custom-switch" label="Check this switch" /> <Form.Check ...

Handling image errors in jQuery for responsive design queries

Images on my website change based on the screen size using media queries. I am looking for a way to handle errors that may occur using jQuery. I want to display a text message if the image fails to load. Here is the code I have so far: <div class="con ...

What is the best way to retrieve dynamically generated text box values on a JSP page?

I'm facing an issue with retrieving values from dynamically created textboxes in my JSP files. Specifically, my setup includes HTML and Javascript (home.jsp) along with JSP (abc.jsp). Currently, I can only fetch values from initially created textboxe ...

What is the best way to create and deliver favicons using Webpack?

Currently, I am working on a universal React project and I need to serve favicons in an Html.js component that is rendered server-side. I came across this package which automatically generates over 30 different sizes of favicons, and I am interested in us ...

I am creating an HTML page that incorporates p5.js, and the text I'm rendering

It seems like the draw loop is continuously refreshing every x seconds, causing this behavior. Is there a way to slow down or disable the frame update without affecting the video refresh rate? I was thinking of adding an fps counter and implementing an i ...

encountering an issue with the react hook useHistory leading to an error

I recently encountered an issue while implementing useHistory() in my code. Previously, I had used it without any errors, but now I'm getting the following error in this component: Line 6:18: React Hook "useHistory" is called in function "showPost" ...

ui-scroll - unable to return to the start of the list

How can I achieve a scroll downwards and then return to the beginning of the list? I've searched for examples on how to implement ui-scroll back and forth, but none seem to fit my needs. Please assist. You can find the fiddle here: http://jsfiddl ...

Automatically assigning a default dynamic value to a dropdown option using Vue.js

I need to set a default selected value for the select option element, but I am facing difficulty in achieving the desired result. <template> <select v-model="tutor_work.start_year"> <option>{{tutor_work.start_year}}< ...

Having trouble with Array.filter functionality

Despite the multitude of discussions on this topic, I have not been successful in using the Array.filter method to remove an item from a string-based Array. Below is an example of the filter method being used in the context of mutating a Vuex store. UPDAT ...

Having trouble switching states in React

Can anyone assist me with a code issue I'm facing when trying to run it onClick? The desired functionality is for each button to display the names set in the 'useState' state, which should then change to 'Click on close' when click ...