javascript - 如何在 Three.js 中将两个形状绑定(bind)在一起?

标签 javascript 3d three.js

我可以将两个不同的形状绑定(bind)在一起作为一个形状吗?

例如,将球体和圆柱体绑定(bind)在一起?

最佳答案

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

  1. 通过层次结构,您可以使用 add() 函数将一个网格添加到另一个网格
  2. 通过 GeometryUtil 的 merge() 函数将两个 Geometry 对象的顶点和网格合并为一个
  3. 使用支持网格之间 bool 运算和导出的基本 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 a 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 软件包允许对网格进行 bool 运算(例如,通过 ADD 操作将两个网格合并在一起 (meshA + meshB))。尝试在 Blender 中创建一个圆柱体和一个球体(免费和开源),已经有 Three.js导出商。或者,您可以从 3D 编辑器或选择导出合并网格的 .obj 文件,并使用 convert_obj_three脚本。

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

事实证明,有一个很棒的 JavaScript 库专门用于此目的:Constructive Solid Geometry :

CSG library preview from the owner's GitHub page

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

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

Cylinder-sphere union with CSG and Three.js

关于javascript - 如何在 Three.js 中将两个形状绑定(bind)在一起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8322759/

相关文章:

javascript - knockout js删除不起作用

javascript - 如何在 d3 中有 2 个矩形重叠来制作进度条?

c++ - OpenGL:二维四边形应该如何存储/渲染?

three.js - 绕轴旋转对象

javascript - 使用三个js和NSF OpenTopography数据的点云: How do you set up the camera and a controls library to navigate the data?

javascript - 如何通过 li data-val 获取输入隐藏字段中的值

javascript - 如果包含图像作为子项,则设置数据属性

散列 2D、3D 和 nD 向量

javascript - Three.js + 传单 = 3D map ?

javascript - Three.js 未捕获 RangeError : Maximum call stack size exceeded in render loop