在 Three.js 中,
ConvexHull是一个实用工具,用于计算一组点的凸包。凸包是围绕一组点的最小凸多边形或多面体。在三维空间中,ConvexHull通常用于生成由点云包围的凸形几何体。
在 Three.js 中,计算几何体的 凸包(Convex Hull)通常是指找到一个点集的最小凸多面体,它包围了所有的点。Three.js 提供了一个ConvexHull相关的 API,能够帮助开发者从一组点中计算出凸包。
ConvexHull 有六个属性二十一个方法
ConvexHull()
创建一个 ConvexHull 实例。
// 生成随机点云 示例 1
const points = [];
for (let i = 0; i < 30; i++) {
points.push(new THREE.Vector3(
Math.random() * 4 - 2, // X 坐标 [-2, 2]
Math.random() * 4 - 2, // Y 坐标 [-2, 2]
Math.random() * 4 - 2 // Z 坐标 [-2, 2]
));
}
// 验证点云有效性
const validPoints = points.filter(point => {
if (isNaN(point.x) || isNaN(point.y) || isNaN(point.z)) {
console.error('Invalid point detected:', point);
return false;
}
return true;
});
// 去除重复点
const uniquePoints = [];
validPoints.forEach(point => {
if (!uniquePoints.some(p => p.equals(point))) {
uniquePoints.push(point);
}
});
// 显示原始点云
const pointGeometry = new THREE.BufferGeometry().setFromPoints(uniquePoints);
const pointMaterial = new THREE.PointsMaterial({ color: 0x00ff00, size: 0.1 });
const pointCloud = new THREE.Points(pointGeometry, pointMaterial);
scene.add(pointCloud);
// 计算凸包
const hull = new ConvexHull().setFromPoints(uniquePoints);
// 提取顶点和面信息,生成几何体
const vertices = [];
hull.faces.forEach(face => {
if (face.edge) {
let edge = face.edge;
do {
const vertex = edge.head().point;// 获取点的x y z 座标
if (!isNaN(vertex.x) && !isNaN(vertex.y) && !isNaN(vertex.z)) {
vertices.push(vertex.x, vertex.y, vertex.z);
} else {
console.error('Invalid vertex in hull:', vertex);
}
edge = edge.next;
} while (edge !== face.edge);
}
});
// 验证顶点数据
if (vertices.length === 0) {
console.error('No valid vertices extracted for the convex hull.');
} else if (vertices.some(coord => isNaN(coord))) {
console.error('Invalid coordinate found in vertices:', vertices);
}
// 创建凸包几何体
const hullGeometry = new THREE.BufferGeometry();
if (vertices.length > 0) {
hullGeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
try {
hullGeometry.computeBoundingSphere(); // 确保没有 NaN 错误
} catch (e) {
console.error('Error computing bounding sphere:', e);
}
} else {
console.error('No vertices available for geometry.');
}
// 创建网格并添加到场景
const hullMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000,
transparent: true,
opacity: 0.5,
side: THREE.DoubleSide,
});
const hullMesh = new THREE.Mesh(hullGeometry, hullMaterial);
scene.add(hullMesh);
// 生成随机点云 示例 2
const points = [];
for (let i = 0; i < 30; i++) {
points.push(new THREE.Vector3(
Math.random() * 4 - 2, // X 坐标 [-2, 2]
Math.random() * 4 - 2, // Y 坐标 [-2, 2]
Math.random() * 4 - 2 // Z 坐标 [-2, 2]
));
}
// 验证点云有效性
const validPoints = points.filter(point => {
if (isNaN(point.x) || isNaN(point.y) || isNaN(point.z)) {
console.error('Invalid point detected:', point);
return false;
}
return true;
});
// 去除重复点
const uniquePoints = [];
validPoints.forEach(point => {
if (!uniquePoints.some(p => p.equals(point))) {
uniquePoints.push(point);
}
});
// 使用 THREE.ConvexGeometry 创建凸包几何体
const convexGeometry = new ConvexGeometry(uniquePoints);
// 创建凸包网格并添加到场景
const hullMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000,
transparent: true,
opacity: 0.5,
side: THREE.DoubleSide,
});
const hullMesh = new THREE.Mesh(convexGeometry, hullMaterial);
scene.add(hullMesh);
属性
- assigned : VertexList 该 vertex list 包含分配给面的所有顶点。默认是一个空的顶点列表。
- faces : Array 生成的凸包面。默认是一个空数组。
- newFaces : Array 该数组保存在单次迭代中生成的面。默认是一个空数组。
- tolerance : Float 用于内部比较运算的 epsilon 值。该值的计算取决于几何形状的大小。默认值为 -1。
- unassigned : VertexList 该 vertex list 包含未分配给面的所有顶点。默认是一个空的顶点列表。
- vertices : Array 给定几何数据的内部表示( vertices 数组)。
方法
- addAdjoiningFace ( eyeVertex : VertexNode, horizonEdge : HalfEdge ) : HalfEdge eyeVertex - 添加到凸包的顶点。 horizonEdge - 地平线的单个边缘。创建一个面,顶点顺序为 'eyeVertex.point'、'horizonEdge.tail' 和 'horizonEdge.head',顺序为逆时针(CCW)。所有半边按照逆时针顺序创建,因此该面始终指向凸包的外部。
- addNewFaces ( eyeVertex : VertexNode, horizonEdge : HalfEdge ) : this eyeVertex - 添加到凸包的顶点。 horizon - 形成地平线的半边数组。 将 'horizon.length' 个面添加到凸包,每个面将与地平线上的相对面以及左/右相邻的面连接。
- addVertexToFace ( vertex : VertexNode, face : Face ) : this vertex - 要添加的顶点。 face - 目标面。 将一个顶点添加到 “分配(assigned)” 顶点列表,并将其分配给给定的面。
- addVertexToHull ( eyeVertex : VertexNode ) : this eyeVertex - 添加到凸包的顶点。 使用以下算法向凸包添加顶点:
- 计算“地平线”,这是一系列半边。要使一条边属于这个组,它必须是连接一个能够看到 'eyeVertex' 的面和一个不能看到 'eyeVertex' 的面的边。
- 所有能够看到 'eyeVertex' 的面都会从已分配顶点列表中移除其可见的顶点。
- 使用“地平线”和 'eyeVertex' 的每条边创建一组新的面。每个面都与相对的地平线面以及左/右相邻的面连接。
- 从所有可见面中移除的顶点将被分配给新的面,如果可能的话。
- cleanup () : this 计算凸包后清理内部属性。
- compute () : this 开始执行快速凸包算法。
- computeExtremes () : Object 计算将用于计算初始凸包的极值(最小/最大向量)。
- computeHorizon ( eyePoint : Vector3, crossEdge : HalfEdge, face : Face, horizon : Array ) : this 计算一个逆时针(CCW)顺序的半边链,称为“地平线”('horizon')。要使一条边成为地平线的一部分,它必须连接一个能够看到 'eyePoint' 的面和一个不能看到 'eyePoint' 的面。
- eyePoint - 点的 3D 坐标。
- crossEdge - 用于跳转到当前面的边。
- face - 当前正在测试的面。
- horizon - 按 CCW 顺序构成地平线一部分的边。
- computeInitialHull () : this 计算初始的单纯形,将所有可能成为凸包一部分的点分配给其面。
- containsPoint ( point : Vector3 ) : this point - 3D 空间中的一个点。 返回 true 如果定点在此凸包内。
- deleteFaceVertices ( face : Face, absorbingFace : Face ) : this face - 给定的面。 absorbingFace - 尝试吸收第一个面的顶点的可选面。 删除 “面(face)” 能够看到的所有可见顶点。
- 如果 'absorbingFace' 不存在,则所有已移除的顶点将被添加到 'unassigned' 顶点列表。
- 如果 'absorbingFace' 存在,则该方法将分配所有 'face' 中可以看到 'absorbingFace' 的顶点。
- 如果一个顶点不能看到 'absorbingFace',则将其添加到 'unassigned' 顶点列表。
- intersectRay ( ray : Ray, target : Vector3 ) : Vector3 ray - 给定的射线。 target - 表示交点的目标向量。 与该凸包执行光线相交测试。如果没有找到交集则返回 null。
- makeEmpty () : this 使这个凸包为空。
- nextVertexToAdd () : VertexNode 查找下一个顶点以使用当前凸包创建面。
- 让初始面成为存在于“已分配(assigned)”顶点列表中的第一个面。
- 如果面不存在则返回,因为没有顶点剩下。
- 否则,对于面能看到的每个顶点,找到距离它最远的那个。
- reindexFaces () : this 从内部面列表中移除不活跃的(例如已删除的)面。
- removeAllVerticesFromFace ( face : Face ) : VertexNode face - 给定的面。 移除给定面能够看到的所有可见顶点,这些顶点存储在“已分配(assigned)”顶点列表中。
- removeVertexFromFace ( vertex : VertexNode, face : Face ) : this vertex - 要删除的顶点。 face - 目标面。 从“已分配”顶点列表和给定面中移除一个顶点。在移除后,它还确保从“面”到它在“已分配”中看到的第一个顶点的链接被正确连接。
- resolveUnassignedPoints ( newFaces : Array ) : this newFaces - 一组新的面。 尽可能从未分配的顶点列表中重新分配顶点给新的面。
- setFromObject ( object : Object3D ) : this object - 用于计算凸包的 Object3D 计算 Object3D 的凸包(包括其子元素),考虑到对象及其子元素的世界变换。
- setFromPoints ( points : Array ) : this points - 生成的凸包将包含的 Vector3s 数组 计算给定点数组的凸包。