Exploring various substances when combining shapes in Three.js enhances the visual appeal and complexity of

I have a vision to construct a Pine tree using 2 different meshes - one for the trunk and another for the bush. Here is what I have tried so far:

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 positioning of the Pine tree is exactly as desired. However, after merging both meshes, the whole shape is only using the material of the first mesh. My goal is to have each mesh retain its respective material post-merger.

What am I missing here? Any helpful insights?

Answer №1

Through extensive research, I came to the realization that a crucial parameter was missing when using the 'merge' method with the Geometry object. This missing parameter is the index of the material that corresponds to the mesh within the materials array. For instance, 0 represents the first material in the 'materials' array, and so forth.

As a result, my final code snippet appears as follows:

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

(Take note of the additional numbers provided for each merge operation).

However, it's important to emphasize that this approach is effective only when merging geometries of the same type. In our case, we are merging two CylinderGeometries. If we attempted to merge, for example, a Cylinder with a Box while including MeshFaceMaterial, it would not be interpreted correctly, resulting in a console error stating 'Cannot read property map/attributes from undefined'. Despite this limitation, merging both geometries without specifying multiple materials is still possible (a mistake I learned the hard way).

I hope this explanation proves helpful to anyone facing similar challenges.

Answer №2

Check out this handy function for combining meshes and their respective materials, plus the option to output as a buffer geometry.

function _combineMeshes(meshes, useBufferGeometry) {

    var resultGeometry,
        allMaterials = [],
        mergedGeometry = new THREE.Geometry(),
        mergedMaterial,
        combinedMesh;

    meshes.forEach(function(mesh, index) {
        mesh.updateMatrix();
        mesh.geometry.faces.forEach(function(face) {face.materialIndex = 0;});
        mergedGeometry.merge(mesh.geometry, mesh.matrix, index);
        allMaterials.push(mesh.material);
    });

    mergedGeometry.groupsNeedUpdate = true;
    mergedMaterial = new THREE.MeshFaceMaterial(allMaterials);

    if (useBufferGeometry) {
        resultGeometry = new THREE.BufferGeometry().fromGeometry(mergedGeometry);
    } else {
        resultGeometry = mergedGeometry;
    }

    combinedMesh = new THREE.Mesh(resultGeometry, mergedMaterial);
    combinedMesh.geometry.computeFaceNormals();
    combinedMesh.geometry.computeVertexNormals();

    return combinedMesh;

}

var combinedMesh = _combineMeshes([trunkMesh, treeTopMesh], true);

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

Add the attribute's value to an array

$(document).ready(function() { function randomColor() { return 'rgb(' + Math.round(Math.random() * 255) + ', ' + Math.round(Math.random() * 255) + ', ' + Math.round(Math.random() * 255) + ')' ...

What is the best way to showcase current elements using Vue.js and firebase without them being outdated?

When working with Firebase, I was able to successfully retrieve and print out a list of events. However, now I'm facing a challenge - I want to load only the "Events" that are not outdated. Any suggestions or tips on how to achieve this? I'd grea ...

Loop over JSON data using JQuery

I am struggling to extract color names and hex values from JSON data obtained from an external source. Despite creating a jsfiddle to troubleshoot, I am stuck as I can't even trigger the alert('hi'); function. Ideally, I need a list of color ...

Using JavaScript to halt the playback of HTML5 video in 'injected' HTML code

Although I know there have been similar issues resolved here before, none of the suggested solutions seem to work for me. Let me start by explaining my problem. I have a landing page located here: On the portfolio section of the landing page, I hav ...

When the button is clicked, I would like to use JavaScript to toggle the visibility of a div, allowing it to open and

I am attempting to toggle a div using JavaScript when the open and close button is clicked. However, I have encountered an issue where the div disappears when the button is clicked, possibly due to post-back. var toggle = function () { var mydiv = d ...

Activate fancybox when clicked, triggering numerous ajax requests

Although I achieved my desired output, the method in which it was done is not ideal because AJAX duplicates with every click. Check out my code: <a href="/messages/schedule" class="greenbtn fancybox">Schedule</a> $('a.fancybox').cl ...

Is there a way to validate form input before inserting it into a database using the onsubmit event?

Looking for a way to enhance the verification process of my signup form, I aim to ensure that all data entered is validated before being saved in the database. The validation process involves checking if the phone number consists only of numerical values a ...

Executing a custom object function in AngularJS by using the ng-click directive

As I navigate my way through AngularJS, I find myself grappling with the concept of calling a custom method of an object and wonder if there's a simpler approach: https://jsfiddle.net/f4ew9csr/3/ <div ng-app="myApp" ng-controller="myCtrl as myCtr ...

When the icon is clicked using `ngClick`, we are triggering the `refresh` event, but unfortunately, it is not functioning as expected

Currently, I am utilizing Angular and jQuery float to create a canvas graph. The graph itself is composed of canvas elements. The issue at hand involves the desire to redraw the canvas upon clicking on a specific icon. The click event handler in question ...

Updating the DOM with an EventListener in Angular 5 is not functioning properly

Situation : Utilizing an Angular PWA for communication with an iOS native app via WKWebview. Implementing messageHandlers to facilitate data sharing between TypeScript and Swift logic code. Issue : Employing addEventListener to monitor a specific event on ...

What is the best way to address ng-invalid and ng-pristine in Angular validation?

I am encountering an issue with angular validation. My scenario is as follows: In a form, I have 2 textfields and 1 button. Upon page load, the button is disabled due to the ng-invalid status. When some text is entered in a textfield, the button becomes ...

Guide to deploying a factory contract using solidity @0.5.0 with Node.js

Repository: https://github.com/aljmiller87/ethereum-dispute-resolution In my solidity file @0.5.0, I have a Factory Contract and a child contract. Although I am able to compile it with some trial and error noted in the commented-out lines in ethereum/comp ...

Simple steps to turn off error highlighting for TypeScript code in Visual Studio Code

Hey there! I've encountered an issue with vscode where it highlights valid code in red when using the union operator '??' or optional chaining '?.'. The code still builds without errors, but vscode displays a hover error message st ...

Error: The value of data.isbn is not defined

After encountering the error message below: TypeError: data.isbn is undefined I modified the code to include the data.isbn == null condition as shown below: $.ajax({ type: "POST", url: "getInventory.php", datatype: "json", data: ({skuSta ...

The problem with reflect-metadata - __webpack_require__ arises from the absence of the 'Require' definition

I'm facing an issue while trying to launch my angular app in Visual Studio. It seems to be stuck on the "Loading..." section. Upon checking Chrome's error console, I came across the following error: https://i.sstatic.net/1aSZT.jpg Uncaught R ...

Exploring Shadertoy's Visual Magic with THREE.js

I am currently attempting to implement this shader on a canvas using THREE.js: . The function I am using usually works for simpler shaders, but for this one, I might need to save the floats as uniforms. I am a bit stuck on this issue. Has anyone encounte ...

Implementing a rate limit on the login API that is specific to individual IP addresses rather than being

I have successfully implemented the [email protected] module, but I am facing an issue where it is blocking the API globally instead of for a specific API that is receiving hits. This is my current code: const limiter = new RateLimit({ windo ...

jQuery does not allow for text input values to be posted

Having an issue with a form using the POST method. I have some PHP controls that are being calculated in jQuery. While all the form control values are accessible in the next form using POST, the values added through jQuery are not posting to the next form. ...

What is the best way to arrange an array of identical objects based on a specific sub property?

Here's an array of items to work with: myArray = [ { someDate: "2018-01-11T00:00:00", name: "John Smith", level: 5000 }, { someDate: "2017-12-18T00:00:00", name: "Jane Doe", level: 1000 }, { ...