Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use multiple materials for merged geometries in Three.js

I want to create a Pine using 2 meshes, 1 for the trunk and another one for the bush, this what I've done:

var pine_geometry = new THREE.Geometry();

var pine_texture_1 = THREE.ImageUtils.loadTexture('./res/textures/4.jpg');
var pine_geometry_1 = new THREE.CylinderGeometry(25, 25, 50, 6);
var pine_material_1 = new THREE.MeshBasicMaterial({
  map : pine_texture_1
});

var pine_1 = new THREE.Mesh(pine_geometry_1);
pine_1.position.x = x;
pine_1.position.y = y + 25;
pine_1.position.z = z;

pine_1.updateMatrix();
pine_geometry.merge(pine_1.geometry, pine_1.matrix);

var pine_texture_2 = THREE.ImageUtils.loadTexture('./res/textures/5.jpg');
var pine_geometry_2 = new THREE.CylinderGeometry(0, 70, 250, 8);
var pine_material_2 = new THREE.MeshBasicMaterial({
  map : pine_texture_2
});

var pine_2 = new THREE.Mesh(pine_geometry_2);
pine_2.position.x = x;
pine_2.position.y = y + 175;
pine_2.position.z = z;

pine_2.updateMatrix();
pine_geometry.merge(pine_2.geometry, pine_2.matrix);

var pine = new THREE.Mesh(pine_geometry, new THREE.MeshFaceMaterial([pine_material_1, pine_material_2]));
pine.geometry.computeFaceNormals();
pine.geometry.computeVertexNormals();

Game.scene.add(pine);

The Pine is correctly positioned as I want, however, the whole merged shape only uses 1 material instead of the 2 (the whole shape is covered by the 1st) and I want that each mesh has it's respective material when mergin both.

What I'm doing wrong? any idea?

like image 293
Edgar Alexander Avatar asked Nov 30 '14 19:11

Edgar Alexander


1 Answers

After a long research I discovered that I was missing an extra parameter for the method 'merge' from the Geometry object, the last parameter is the index of the material that the mesh must have from the materials array, ex: 0 -> first material in 'materials' array... and so on.

So, my final piece of code looks like:

pine_geometry.merge(pine_1.geometry, pine_1.matrix, 0);

var pine_texture_2 = THREE.ImageUtils.loadTexture('./res/textures/5.jpg');
var pine_geometry_2 = new THREE.CylinderGeometry(0, 70, 250, 8);
var pine_material_2 = new THREE.MeshBasicMaterial({
  map : pine_texture_2
});

var pine_2 = new THREE.Mesh(pine_geometry_2);
pine_2.position.x = x;
pine_2.position.y = y + 175;
pine_2.position.z = z;

pine_2.updateMatrix();
pine_geometry.merge(pine_2.geometry, pine_2.matrix, 1);

(Note the last numbers I add to each merge).

However, I want to clarify that this practice only works when we are dealing with various geometries that are from the same type, in this case, we're merging two CylinderGeometry, but if we wanted to merge for example a Cylinder with a Box AND add the MeshFaceMaterial, it wouldn't be recognized properly and the console will throw us 'Cannot read property map/attributes from undefined', nevertheless we can still merge both geometries but not providing multiple materials (that's a terrible mistake I made).

Hope this helps to anyone.

like image 109
Edgar Alexander Avatar answered Sep 28 '22 21:09

Edgar Alexander