web-dev-qa-db-fra.com

Comment fusionner deux géométries ou des maillages avec three.js r71?

Ici, je me suis heurté au problème car je dois fusionner deux géométries (ou mailles) en une. En utilisant les versions précédentes de three.js, il existait une fonction Nice:

THREE.GeometryUtils.merge(pendulum, ball);

Cependant, ce n'est plus sur la nouvelle version.

J'ai essayé de fusionner pendulum et ball avec le code suivant:

ball est un maillage.

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

Après tout, j'ai eu l'erreur suivante:

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
23

Enfin, j'ai trouvé une solution possible. Je poste car cela pourrait être utile à quelqu'un d'autre alors que j'ai perdu beaucoup d'heures. La difficulté réside dans la manipulation du concept de maillage et de géométries:

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

Pour expliquer plus clairement la réponse de Darius (alors que je tentais de mettre à jour une version de la ville procédurale de M. Doob afin qu'elle fonctionne avec les cases Face3):

Essentiellement, vous fusionnez tous vos maillages en une seule géométrie. Donc, si vous voulez, par exemple, fusionner une boîte et une sphère:

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

... dans une seule géométrie:

var singleGeometry = new THREE.Geometry();

... vous créez un maillage pour chaque géométrie:

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

... appelez ensuite la méthode de fusion de la géométrie unique pour chacune, en passant la géométrie et la matrice de chacune dans la méthode:

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

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

Une fois la fusion effectuée, créez un maillage à partir de la géométrie unique et ajoutez-le à la scène:

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

Un exemple de travail:

<!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>

Au moins, c'est comme ça que j'interprète les choses; Toutes mes excuses à tout le monde si quelque chose ne va pas car je ne suis pas près d’être un expert de trois ans (en cours d’apprentissage). J'ai juste eu la "malchance" de m'essayer à la personnalisation du code de ville procédural de M. Doob, lorsque la dernière version casse des problèmes (le principe de fusion étant l'un d'entre eux, le fait que three.js n'utilise plus les quads pour cube -ahem - géométrie de la boîte l'autre - ce qui a conduit à toutes sortes de plaisir à obtenir l'ombrage et tel pour fonctionner à nouveau correctement).

30
Andrew Ayers

Le message d'erreur est correct. CylinderGeometry n'est pas un Object3D. Mesh est. Un maillage est construit à partir d'une géométrie et d'un matériau. Un maillage peut être ajouté à la scène, alors qu'une géométrie ne le peut pas.

Dans les dernières versions de three.js, Geometry utilise deux méthodes de fusion: merge et mergeMesh .

  • merge prend un argument obligatoire geometry et deux arguments optionnels matrix et materialIndexOffset .
  • geom. mergeMesh (maillage) est un raccourci pour geom. merge (maillage. géométrie , maillage. matrice ), utilisé dans d'autres réponses. ('geom' et 'mesh' sont des noms arbitraires pour une géométrie et un maillage, respectivement.) Le matériau du maillage est ignoré.
5
Elias Hasle

Ceci est ma version compacte ultime en quatre (ou cinq) lignes (tant que le matériau est défini ailleurs) en utilisant mergeMesh:

var geom = new THREE.Geometry();
geom.mergeMesh(new THREE.Mesh(new THREE.BoxGeometry(2,20,2)));
geom.mergeMesh(new THREE.Mesh(new THREE.BoxGeometry(5,5,5)));
geom.mergeVertices(); // optional
scene.add(new THREE.Mesh(geom, material));

Edit: ajout d’une ligne supplémentaire facultative pour supprimer les sommets en double, ce qui devrait améliorer les performances.

Edit 2: J'utilise la dernière version, 94. 

0
Rob Kwasowski