Trois matériaux multiples sur un objet chargé via OBJMTLLoader

J'ai des fichiers ".obj" et ".mtl" d'un modèle et je le charge via OBJMTLLoader . ".mtl" spécifie la texture à appliquer à un modèle, et trois.js charge le modèle et le rend avec une texture appliquée très bien.

Mais voici la chose.

Une fois qu'un objet est chargé, j'aimerais appliquer une autre texture sur celui-ci. C'est parce que la première texture représente le matériau de surface d'un objet. Et la deuxième texture est un dessin, que je voudrais positionner à un emplacement spécifique sur un modèle.

Ma question est la suivante: comment appliquer une deuxième texture sur un objet déjà chargé (et texturé) ?

Je vois que trois.js crée une instance de THREE.Object3D , et cette instance a un réseau "enfants" avec une instance de THREE.Mesh .

Lorsque j'essaie d'appliquer une texture à ce maillage ( mesh.material.map = texture ), je perds la texture initiale.

J'ai examiné cette question concernant l'application de multiples textures et JSONLoader, mais je n'ai pas trouvé de réponse.

J'ai également essayé d'utiliser le new THREE.MeshFaceMaterial( materials ) (comme suggéré dans cette réponse ) mais sans succès.

MISE À JOUR :

J'ai essayé la suggestion de @ WestLangley d'utiliser un objet multi-matériel, mais je suis toujours incapable de rendre un matériau au-dessus d'un autre.

J'ai fait cette démonstration simple, adaptée de trois.js OBJLoader – http://dl.dropboxusercontent.com/u/822184/webgl_multiple_texture/index.html

J'utilise THREE.SceneUtils.createMultiMaterialObject comme suggéré, en passant la géométrie clonée du maillage principal chargée de .obj. Je lui donne également 2 textures – une pour toute la surface, une autre – pour la surface avant du modèle.

Mais cela ne fonctionne pas. J'ai ajouté 2 cases qui basculent la propriété "visible" des matériaux correspondants. Vous pouvez voir que les matériaux sont présents, mais je ne vois pas le premier de dessous du second.

Le point crucial du chargement / rendu est le suivant:

 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' ); 

MISE À JOUR # 2

À ce stade, je pense que le meilleur moyen est d'utiliser THREE.ShaderMaterial pour appliquer une texture sur une autre. Je vois quelques exemples d'utilisation d'une seule texture, mais je ne sais toujours pas comment afficher les deux en état superposé. Je ne sais pas non plus comment positionner la texture à un emplacement spécifique sur un maillage.

Vous avez plusieurs choix:

  1. Vous pouvez mélanger les images du côté javascript à l'aide d'outils de toile, et créer un seul matériau avec une seule carte de texture.

  2. Vous pouvez créer un objet multi-matériaux à partir d'une seule géométrie et d'un éventail de matériaux. (Cette approche crée simplement plusieurs maillages identiques, chacun avec l'un des matériaux, et est généralement utilisé lorsque l'un des matériaux est un cadre filaire. Il peut également fonctionner correctement si un matériau est transparent.)

    THREE.SceneUtils.createMultiMaterialObject( geometry, materials );

  3. Vous pouvez obtenir un effet multi-texture avec un ShaderMaterial personnalisée. Avoir deux entrées de texture et implémenter un mélange de couleurs dans le shader.

Voici un exemple d'un simple ShaderMaterial de ShaderMaterial plus simple qui implémente le mélange de deux textures: https://jsfiddle.net/6bg4qdhx/3/ .

EDIT: violon mis à jour à trois.js r.85

EDIT: les ressources de violon ont été modifiées pour être chargées via https

Votre objet chargé a la géométrie (avec ses sommets, ses visages et ses UV) et son matériau. Créez ShaderMaterial qui combine les textures d'une manière qui vous convient et crée une maille avec la géométrie à partir de l'objet chargé.

Utilisez ShaderMaterial et définissez les deux textures comme uniformes, puis mélangez-les au sein de shader.

Donc, vous créez 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 }); 

Et créez un maillage avec ce matériel:

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

Vous pouvez mettre le masque vertex le plus simple:

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

Et fragment shader qui fera réellement le mélange:

 #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); }