Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to merge two geometries or meshes using three.js r71?

Here I bumped to the problem since I need to merge two geometries (or meshes) to one. Using the earlier versions of three.js there was a nice function:

THREE.GeometryUtils.merge(pendulum, ball); 

However, it is not on the new version anymore.

I tried to merge pendulum and ball with the following code:

ball is a mesh.

var ballGeo = new THREE.SphereGeometry(24,35,35); var ballMat = new THREE.MeshPhongMaterial({color: 0xF7FE2E});  var ball = new THREE.Mesh(ballGeo, ballMat);  ball.position.set(0,0,0);  var pendulum = new THREE.CylinderGeometry(1, 1, 20, 16); ball.updateMatrix(); pendulum.merge(ball.geometry, ball.matrix); scene.add(pendulum); 

After all, I got the following error:

THREE.Object3D.add: object not an instance of THREE.Object3D. THREE.CylinderGeometry {uuid: "688B0EB1-70F7-4C51-86DB-5B1B90A8A24C", name: "", type: "CylinderGeometry", vertices: Array[1332], colors: Array[0]…}THREE.error @ three_r71.js:35THREE.Object3D.add @ three_r71.js:7770(anonymous function) @ pendulum.js:20 
like image 891
Darius Miliauskas Avatar asked May 14 '15 19:05

Darius Miliauskas


People also ask

What is a mesh in three Js?

A Three. js Mesh is a base class that inherits from Object3d and is used to instantiate polygonal objects by combining a Geometry with a Material. Mesh is also the base class for the more advanced MorphAnimMesh and SkinnedMesh classes.


2 Answers

To explain Darius' answer more clearly (as I struggled with it, while trying to update a version of Mr Doob's procedural city to work with the Face3 boxes):

Essentially you are merging all of your Meshes into a single Geometry. So, if you, for instance, want to merge a box and sphere:

var box = new THREE.BoxGeometry(1, 1, 1); var sphere = new THREE.SphereGeometry(.65, 32, 32); 

...into a single geometry:

var singleGeometry = new THREE.Geometry(); 

...you would create a Mesh for each geometry:

var boxMesh = new THREE.Mesh(box); var sphereMesh = new THREE.Mesh(sphere); 

...then call the merge method of the single geometry for each, passing the geometry and matrix of each into the method:

boxMesh.updateMatrix(); // as needed singleGeometry.merge(boxMesh.geometry, boxMesh.matrix);  sphereMesh.updateMatrix(); // as needed singleGeometry.merge(sphereMesh.geometry, sphereMesh.matrix); 

Once merged, create a mesh from the single geometry and add to the scene:

var material = new THREE.MeshPhongMaterial({color: 0xFF0000}); var mesh = new THREE.Mesh(singleGeometry, material); scene.add(mesh); 

A working example:

<!DOCTYPE html>  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.js"></script>  <!-- OrbitControls.js is not versioned and may stop working with r77 -->  <script src='http://threejs.org/examples/js/controls/OrbitControls.js'></script>    <body style='margin: 0px; background-color: #bbbbbb; overflow: hidden;'>    <script>      // init renderer      var renderer = new THREE.WebGLRenderer();      renderer.setSize(window.innerWidth, window.innerHeight);      document.body.appendChild(renderer.domElement);        // init scene and camera      var scene = new THREE.Scene();      var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 3000);      camera.position.z = 5;      var controls = new THREE.OrbitControls(camera)     	      // our code      var box = new THREE.BoxGeometry(1, 1, 1);      var sphere = new THREE.SphereGeometry(.65, 32, 32);        var singleGeometry = new THREE.Geometry();        var boxMesh = new THREE.Mesh(box);      var sphereMesh = new THREE.Mesh(sphere);        boxMesh.updateMatrix(); // as needed      singleGeometry.merge(boxMesh.geometry, boxMesh.matrix);        sphereMesh.updateMatrix(); // as needed      singleGeometry.merge(sphereMesh.geometry, sphereMesh.matrix);        var material = new THREE.MeshPhongMaterial({color: 0xFF0000});      var mesh = new THREE.Mesh(singleGeometry, material);      scene.add(mesh);        // a light      var light = new THREE.HemisphereLight(0xfffff0, 0x101020, 1.25);      light.position.set(0.75, 1, 0.25);      scene.add(light);  	      // render      requestAnimationFrame(function animate(){  	    requestAnimationFrame(animate);  	    renderer.render(scene, camera);		      })    </script>  </body>

At least, that's how I am interpreting things; apologies to anyone if I have something wrong, as I am no where close to being a three.js expert (currently learning). I just had the "bad luck" to try my hand at customizing Mr. Doob's procedural city code, when the latest version breaks things (the merge stuff being one of them, the fact that three.js no longer uses quads for cube -ahem- box geometry the other - which has led to all kinds of fun getting the shading and such to work properly again).

like image 198
Andrew Ayers Avatar answered Sep 19 '22 18:09

Andrew Ayers


Finally, I found a possible solution. I am posting since it could be useful for somebody else while I wasted a lot of hours. The tricky thing is about manipulating the concept of meshes and geometries:

var ballGeo = new THREE.SphereGeometry(10,35,35); var material = new THREE.MeshPhongMaterial({color: 0xF7FE2E});  var ball = new THREE.Mesh(ballGeo, material);  var pendulumGeo = new THREE.CylinderGeometry(1, 1, 50, 16); ball.updateMatrix(); pendulumGeo.merge(ball.geometry, ball.matrix);  var pendulum = new THREE.Mesh(pendulumGeo, material); scene.add(pendulum); 
like image 34
Darius Miliauskas Avatar answered Sep 20 '22 18:09

Darius Miliauskas