简体   繁体   English

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

[英]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.js 有一个不错的 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:我尝试使用以下代码合并pendulumball

ball is 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

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): 更清楚地解释Darius的回答(当我努力解决它时,在尝试更新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: ...你会为每个几何创建一个Mesh:

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). 如果我有什么不对的话,向任何人道歉,因为我不是一个接近成为three.js专家(目前正在学习)的地方。 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先生的程序城市代码。 - 另一个盒子几何 - 这使得阴影得到各种乐趣,并且再次正常工作)。

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

The error message is right. 错误消息是正确的。 CylinderGeometry is not an Object3D. CylinderGeometry不是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. 可以将Mesh添加到场景中,而Geometry则不能。

In the newest versions of three.js, Geometry has two merge methods: merge and mergeMesh . 在最新版本的three.js中,Geometry有两种合并方法: mergemergeMes​​h

  • merge takes a mandatory argument geometry , and two optional arguments matrix and materialIndexOffset . merge采用强制参数几何 ,以及两个可选参数matrixmaterialIndexOffset
  • geom. GEOM。 mergeMesh (mesh) is basically a shorthand for geom. mergeMes​​h (mesh)基本上是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. ('geom'和'mesh'分别是Geometry和Mesh的任意名称。)Mesh的材质被忽略。

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。

The answers and code that I've seen posted here do not work because the second argument of the merge method is an integer, not a matrix.我在这里看到的答案和代码不起作用,因为合并方法的第二个参数是 integer,而不是矩阵。 As far as I can tell, the merge method is not really functioning in a useful way.据我所知,合并方法并没有真正发挥作用。 Therefore, I used the following approach to make a simple rocket with a nose cone.因此,我使用以下方法制作了一个带有鼻锥的简单火箭。

import * as BufferGeometryUtils from '../three.js/examples/jsm/utils/BufferGeometryUtils.js'

lengthSegments = 2
radius = 5
radialSegments = 32
const bodyLength = dParamWithUnits['launchVehicleBodyLength'].value
const noseConeLength = dParamWithUnits['launchVehicleNoseConeLength'].value

// Create the vehicle's body
const launchVehicleBodyGeometry = new THREE.CylinderGeometry(radius, radius, bodyLength, radialSegments, lengthSegments, false)
launchVehicleBodyGeometry.name = "body"
// Create the nose cone
const launchVehicleNoseConeGeometry = new THREE.CylinderGeometry(0, radius,  noseConeLength, radialSegments, lengthSegments, false)
launchVehicleNoseConeGeometry.name = "noseCone"
launchVehicleNoseConeGeometry.translate(0, (bodyLength+noseConeLength)/2, 0)
// Merge the nosecone into the body
const launchVehicleGeometry = BufferGeometryUtils.mergeBufferGeometries([launchVehicleBodyGeometry, launchVehicleNoseConeGeometry])
// Rotate the vehicle to horizontal
launchVehicleGeometry.rotateX(-Math.PI/2)
const launchVehicleMaterial = new THREE.MeshPhongMaterial( {color: 0x7f3f00})
const launchVehicleMesh = new THREE.Mesh(launchVehicleGeometry, launchVehicleMaterial)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM