Numerous Three.js materials on an object loaded via OBJMTLLoader

I have the model โ€œ.objโ€ and โ€œ.mtlโ€ files and I upload it via OBJMTLLoader . ".mtl" sets the texture applied to the model, and the three.js model loads the model and makes it fine using the texture.

But here's the thing.

Once the object is loaded, I would like to apply a different texture to it. This is due to the fact that the first texture is the surface material of the object. And the second texture is a picture that I would like to position in a certain place on the model.

My question is: how to apply a second texture to an already loaded (and textured) object ?

I see that three.js creates an instance of THREE.Object3D , and this instance has an array of "children" with one instance of THREE.Mesh .

When I try to apply a texture to this mesh ( mesh.material.map = texture ), I lose the original texture.

I reviewed this question about applying multiple textures and JSONLoader , but did not find an answer.

I also tried using new THREE.MeshFaceMaterial( materials ) (as suggested in this answer ), but to no avail.

UPDATE

I tried @WestLangley's suggestion to use an object with multiple materials, but I still cannot display one material on top of another.

I did this simple demo adapted from three .js OBJLoader - http://dl.dropboxusercontent.com/u/822184/webgl_multiple_texture/index.html

I am using THREE.SceneUtils.createMultiMaterialObject as suggested, passing it the cloned geometry of the main mesh loaded from .obj. I also give him 2 textures - one for the entire surface, the other for the front surface of the model.

But that does not work. I added 2 flags that switch the โ€œvisibleโ€ property of the corresponding materials. You can see that the materials are present, but I do not see the first of them below the second.

The essence of loading / rendering is as follows:

 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 point, I find it best to use THREE.ShaderMaterial to apply one texture to another. I see several examples of using the same texture , but still do not know how to display them in the superimposed state. I'm also not sure how to position the texture in a specific place on the grid.

+7
source share
2 answers

You have several options:

  • You can mix images from the javascript side with canvas tools and create one material with one texture map.

  • You can create an object with several materials from one geometry and an array of materials. (This approach simply creates several identical grids, each with one of the materials, and is usually used when one of the materials is a skeleton. It can also work fine if one material is transparent.)

    THREE.SceneUtils.createMultiMaterialObject( geometry, materials );

  • You can achieve multistructure effects with customizable ShaderMaterial . Have two texture inputs and implement color mixing in the shader.

Here is an example of the roughly simpler tr.js ShaderMaterial method, which implements mixing two textures: https://jsfiddle.net/6bg4qdhx/3/ .

EDIT: fiddle updated to three. js r.85

EDIT: change script resources to download via https

+18
source

A loaded object has geometry (along with its vertices, faces, and UVs) and material. Create a ShaderMaterial that combines the textures in some way that suits you, and create a mesh with geometry from the loaded object.

Use ShaderMaterial and set both textures as uniforms, and then mix them in a shader.

So you create a ShaderMaterial:

 var vertShader = document.getElementById('vertex_shh').innerHTML; var fragShader = document.getElementById('fragment_shh').innerHTML; var attributes = {}; // custom attributes var uniforms = { // custom uniforms (your textures) 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 }); 

And create a grid with this material:

 var me = new THREE.Mesh( my_loaded_model, material_shh ); // you previously loaded geometry of the object 

You can specify the simplest vertex shader:

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

And a fragmented shader that will actually perform the mixing:

 #ifdef GL_ES precision highp float; #endif uniform sampler2D tOne; uniform sampler2D tSec; varying vec2 vUv; void main(void) { vec3 c; vec4 Ca = texture2D(tOne, vUv); vec4 Cb = texture2D(tSec, vUv); c = Ca.rgb * Ca.a + Cb.rgb * Cb.a * (1.0 - Ca.a); // blending equation or wahtever suits you gl_FragColor= vec4(c, 1.0); } 
+1
source

All Articles