Javascript 如何使用three.js r71合并两个几何图形或网格?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30245990/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:51:39  来源:igfitidea点击:

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

javascriptmergethree.js

提问by Darius Miliauskas

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.js 的早期版本有一个很好的功能:

THREE.GeometryUtils.merge(pendulum, ball);

However, it is not on the new version anymore.

但是,它不再出现在新版本中。

I tried to merge pendulumand ballwith the following code:

我尝试合并pendulumball使用以下代码:

ballis a mesh.

ball是一个网格。

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

采纳答案by Darius Miliauskas

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

回答by Andrew Ayers

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

为了更清楚地解释大流士的答案(因为我在尝试更新 Doob 先生的程序城市版本以使用 Face3 盒子时,我一直在努力解决这个问题):

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

至少,我是这样解释事物的;如果我有什么问题,向任何人道歉,因为我离成为一个 Three.js 专家还差得很远(目前正在学习)。我只是“运气不好”尝试自定义 Doob 先生的程序城市代码,当最新版本破坏了一些东西(合并的东西就是其中之一,事实上,three.js 不再使用四边形作为立方体 -ahem - 另一个盒子几何体 - 这导致了获得阴影等各种乐趣,以便再次正常工作)。

回答by Elias Hasle

The error message is right. CylinderGeometry is not an Object3D. Mesh is. A Mesh is constructed from a Geometry and a Material. A Mesh can be added to the scene, while a Geometry cannot.

错误信息是正确的。CylinderGeometry 不是 Object3D。网格是。网格由几何体和材质构成。网格可以添加到场景中,而几何体则不能。

In the newest versions of three.js, Geometry has two merge methods: mergeand mergeMesh.

在three.js 的最新版本中,Geometry 有两种合并方法:mergemergeMes​​h

  • mergetakes a mandatory argument geometry, and two optional arguments matrixand materialIndexOffset.
  • geom.mergeMesh(mesh) is basically a shorthand for geom.merge(mesh.geometry, mesh.matrix), as used in other answers. ('geom' and 'mesh' being arbitrary names for a Geometry and a Mesh, respectively.) The Material of the Mesh is ignored.
  • merge需要一个强制参数geometry和两个可选参数matrixmaterialIndexOffset
  • 几何。mergeMes​​h(mesh)基本上是geom的简写。合并(mesh. geometry, mesh. matrix),如其他答案中所用。(“geom”和“mesh”分别是几何体和网格的任意名称。)网格的材质被忽略。

回答by Rob Kwasowski

This is my ultimate compact version in four (or five) lines (as long as material is defined somewhere else) making use of mergeMesh:

这是我使用mergeMes​​h的四(或五)行(只要材料在其他地方定义)的最终紧凑版本:

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: added optional extra line to remove duplicate vertices, which should help performance.

编辑:添加了可选的额外行以删除重复的顶点,这应该有助于提高性能。

Edit 2: I'm using the newest version, 94.

编辑 2:我使用的是最新版本 94。