Use multiple materials for merged geometries in Three.js

I want to create a pine using 2 cells, 1 for the trunk and another for the bush, this is what I did:

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 positioned correctly the way I want, however the whole combined shape uses only 1 material instead of 2 (the whole shape is covered by the 1st), and I want each grid to have the corresponding material when merging both.

What am I doing wrong? any idea?

+6
source share
2 answers

After a long study, I found that I do not have an additional parameter for the 'merge' method from the Geometry object, the last parameter is the index of the material that the grid from the array of materials should have, for example: 0 → the first material in the array of materials, etc.

So my last piece of code looks like this:

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

(Pay attention to the latest numbers that I add for each merge).

However, I want to clarify that this practice only works when we deal with different geometries of the same type, in this case we combine two CylinderGeometry , but if we want to combine, for example, a cylinder with a box and add MeshFaceMaterial, it will not be recognized properly, and the console will throw us “Cannot read map / property attributes from undefined”, however, we can still combine both geometries, but not provide several materials (this is a terrible mistake I made).

Hope this helps anyone.

+7
source

Here's a common function for combining meshes with materials. You can also specify whether you want to return it as buffer geometry.

 function _mergeMeshes(meshes, toBufferGeometry) { var finalGeometry, materials = [], mergedGeometry = new THREE.Geometry(), mergeMaterial, mergedMesh; meshes.forEach(function(mesh, index) { mesh.updateMatrix(); mesh.geometry.faces.forEach(function(face) {face.materialIndex = 0;}); mergedGeometry.merge(mesh.geometry, mesh.matrix, index); materials.push(mesh.material); }); mergedGeometry.groupsNeedUpdate = true; mergeMaterial = new THREE.MeshFaceMaterial(materials); if (toBufferGeometry) { finalGeometry = new THREE.BufferGeometry().fromGeometry(mergedGeometry); } else { finalGeometry = mergedGeometry; } mergedMesh = new THREE.Mesh(finalGeometry, mergeMaterial); mergedMesh.geometry.computeFaceNormals(); mergedMesh.geometry.computeVertexNormals(); return mergedMesh; } var mergedMesh = _mergeMeshes([trunkMesh, treeTopMesh], true); 
0
source

Source: https://habr.com/ru/post/978905/


All Articles