Three.js - 将两个形状绑定在一起?

Posted

技术标签:

【中文标题】Three.js - 将两个形状绑定在一起?【英文标题】:Three.js - bind two shapes together as one? 【发布时间】:2012-01-09 12:01:19 【问题描述】:

我是three.js 世界的新手... 我的问题是:我可以将两个不同的形状绑定在一起作为一个形状吗? 比如将球体和圆柱体绑定在一起?

【问题讨论】:

【参考方案1】:

有点,是的,有多种选择:

    通过层次结构您可以使用add() 函数简单地将一个网格添加到另一个网格 通过 GeometryUtil 的 merge() 函数将两个 Geometry 对象的顶点和网格合并为一个 使用支持网格和导出之间的布尔运算的基本 3D 编辑器。

方法 1 非常简单:

var sphere = new THREE.Mesh( new THREE.SphereGeometry(100,16,12),new THREE.MeshLambertMaterial(  color: 0x2D303D, wireframe: true, shading: THREE.FlatShading  ));
                var cylinder = new THREE.Mesh(new THREE.CylinderGeometry(100, 100, 200, 16, 4, false ),new THREE.MeshLambertMaterial(  color: 0x2D303D, wireframe: true, shading: THREE.FlatShading  ));
                cylinder.position.y = -100;
                scene.add(sphere);
                scene.add(cylinder);

注意 16 是重复的,因此一个网格中的细分级别与另一个网格相匹配(看起来不错)

方法 2.1 - 通过 GeometryUtils

//make a sphere
                var sg = new THREE.SphereGeometry(100,16,12);
                //make cylinder - ideally the segmentation would be similar to predictable results
                var cg = new THREE.CylinderGeometry(100, 100, 200, 16, 4, false );
                //move vertices down for cylinder, so it maches half the sphere - offset pivot
                for(var i = 0 ; i < cg.vertices.length; i++) cg.vertices[i].position.y -= 100;
                //merge meshes
                THREE.GeometryUtils.merge(sg,cg);
                var mesh = new THREE.Mesh( sg,new THREE.MeshLambertMaterial(  color: 0x2D303D, wireframe: true, shading: THREE.FlatShading  ));
                scene.add(mesh);

方法2.2合并一个Lathe half-sphere和一个圆柱体:

var pts = [];//points array
                var detail = .1;//half-circle detail - how many angle increments will be used to generate points
                var radius = 100;//radius for half_sphere
                var total = Math.PI * .51;
                for(var angle = 0.0; angle < total ; angle+= detail)//loop from 0.0 radians to PI (0 - 180 degrees)
                    pts.push(new THREE.Vector3(0,Math.cos(angle) * radius,Math.sin(angle) * radius));//angle/radius to x,z
                var lathe = new THREE.LatheGeometry( pts, 16 );//create the lathe with 12 radial repetitions of the profile
                //rotate vertices in lathe geometry by 90 degrees
                var rx90 = new THREE.Matrix4();
                rx90.setRotationFromEuler(new THREE.Vector3(-Math.PI * .5,0,0));
                lathe.applyMatrix(rx90);
                //make cylinder - ideally the segmentation would be similar for predictable results
                var cg = new THREE.CylinderGeometry(100, 100, 200, 16, 4, false );
                //move vertices down for cylinder, so it maches half the sphere
                for(var i = 0 ; i < cg.vertices.length; i++) cg.vertices[i].position.y -= 100;
                //merge meshes
                THREE.GeometryUtils.merge(lathe,cg);
                var mesh = new THREE.Mesh( lathe, new THREE.MeshLambertMaterial(  color: 0x2D303D, wireframe: true, shading: THREE.FlatShading  ) );
                mesh.position.y = 150;
                scene.add(mesh);

我目前无法解决的一个问题来自网格内部的面。理想情况下,它们会翻转法线,因此它们不会渲染,但还没有找到快速的解决方案。

第三个是相当直截了当的。大多数 3D 包允许对网格进行布尔运算(例如,通过 ADD 操作(meshA + meshB)将两个网格合并在一起)。尝试在Blender(免费,开源)中创建一个圆柱体和一个球体,它已经有一个three.js 导出器。或者,您可以从 3d 编辑器或选择中导出合并网格的 .obj 文件,然后使用 convert_obj_three 脚本。

更新

我发现了另一种方法,它可能更容易/更直观。还记得我上面提到的布尔运算吗?

原来有一个很棒的 js 库就是为了这个:Constructive Solid Geometry:

Chandler Prall 编写了一些方便的函数来连接CSG with three.js。因此,使用 CSG 库和 three.js wrapper for it,您可以简单地执行以下操作:

var cylinder = THREE.CSG.toCSG(new THREE.CylinderGeometry(100, 100, 200, 16, 4, false ),new THREE.Vector3(0,-100,0));
var sphere   = THREE.CSG.toCSG(new THREE.SphereGeometry(100,16,12));
var geometry = cylinder.union(sphere);
var mesh     = new THREE.Mesh(THREE.CSG.fromCSG( geometry ),new THREE.MeshNormalMaterial());

这会给你一个很好的结果(额外的面/翻转法线/等没有问题):

【讨论】:

我正在尝试所有这些东西,感谢您的回答!我问了这个问题,因为我正在尝试创建具有多种形状和纹理的 3D 花。我的目的是绑定形状,这样我就可以旋转和拖动整个花朵形状,而不是把每个形状都放在一个形状中 听起来有点像Hello Enjoy's HelloFlower app。在这种情况下,我会说,在顶部有一个空的“容器”Object3D,然后是add() 花瓣、花蕊等,这样您就可以一起操纵该组。类似于第一个建议,但不是直接添加到场景中,而是添加到容器中(scene.add(container);container.add(flowerPartA);container.add(flowerPartB);//etc. 哇!这是一个很好的例子……不完全是我想要构建的东西,但有一些类似的东西。在过去的几天里,我取得了很好的进展。我希望我将发布的最后一个示例能够帮助 Three.js 的初学者解决一些小问题和大问题。但是仍然有一些我仍然不熟悉的小东西......我怎样才能创建像圆柱形状一样的东西,从 X 点开始并在 Y 点结束......现在我唯一能弄清楚的就是制作一个圆柱体并旋转它? @BorisD 是的,旋转是正确的方法!您需要计算旋转,但这很容易,因为 Object3D 有一个 lookAt() 函数, 也有Matrix4 为您完成大部分数学运算。不过有一个问题:圆柱体的默认枢轴位于网格的中心,因此您可能还需要进行一些偏移。几天前我发现了this。尝试使用上面提到的。如果您遇到问题,请尝试重新提出您的问题并根据您的试验再次发布。 HTH 这正是我正在寻找的,但不幸的是,它不适用于 Three.js r50 :( 你知道围绕 CSG 的 three.js 包装器是否已更新?【参考方案2】:

我更新了 THREE.js r62 的包装器,你可以在这里找到它:https://github.com/kraag22/csg-wrapper

【讨论】:

以上是关于Three.js - 将两个形状绑定在一起?的主要内容,如果未能解决你的问题,请参考以下文章

Autodesk Forge 三个 JS 版本支持 ShapeBufferGeometry

如何在three.js中生成具有3个面的形状

在three.js中将带孔的SVG路径转换为挤压形状

针对其中的盒子几何形状进行光线投射(three.js)

如何从 Three.js 画布中保存图像?

three.js 中挤出形状的奇怪工件和空纹理