如何获取构成立方体单个面的三角形组?
获取Three.js BoxGeometry单个面三角形组的正确流程
问题背景
尝试获取Three.js中BoxGeometry构成立方体单个面的三角形组,具体尝试如下:
- 假设BoxGeometry的
groups数组(共6个元素)每个元素对应立方体的一个面,存储该面的构成数据 - 使用以下代码获取第一个group的索引,通过
mesh.getVertexPosition()获取顶点并渲染连线:
const topFaceTrgl = groups[0]; for ( let i = topFaceTrgl.start; i < topFaceTrgl.start + topFaceTrgl.count; i += 3 ) { const v1 = mesh.getVertexPosition( i, new THREE.Vector3() ); const v2 = mesh.getVertexPosition( i + 1, new THREE.Vector3() ); const v3 = mesh.getVertexPosition( i + 2, new THREE.Vector3() ); const lineGeo = new THREE.BufferGeometry(); const lineBufAtrb = new THREE.BufferAttribute( new Float32Array(4 * 3), 3 ); lineBufAtrb.setXYZ(0, v1.x, v1.y, v1.z); lineBufAtrb.setXYZ(1, v2.x, v2.y, v2.z); lineBufAtrb.setXYZ(2, v3.x, v3.y, v3.z); lineBufAtrb.setXYZ(4, v1.x, v1.y, v1.z); lineGeo.setAttribute("position", lineBufAtrb); const lineMat = new THREE.LineBasicMaterial({ color: "white", transparent: true, }); const lineMesh = new THREE.Line(lineGeo, lineMat); scene.add(lineMesh); }
实际渲染结果为杂乱的零散线条,预期是渲染出单个立方体面的矩形轮廓。
正确流程及代码
1. 核心错误分析
mesh.getVertexPosition(i)中的i是索引缓冲区(index buffer)的索引,而非顶点位置数组的直接索引。BoxGeometry会复用顶点,必须先通过index缓冲区拿到实际的顶点位置索引,再去position缓冲区获取坐标。- 绘制三角形轮廓时,顶点索引设置错误(代码中用了索引4,但数组长度仅支持0-3)。
2. 正确实现步骤
- 从BoxGeometry中获取
index和position属性 - 遍历目标group的索引范围,逐个取出三角形的顶点索引
- 通过顶点索引获取对应的三维坐标
- 绘制三角形轮廓或填充三角形
3. 修正后的代码示例
const geometry = mesh.geometry; const index = geometry.index; const position = geometry.attributes.position; // 取第一个面的group数据 const targetGroup = geometry.groups[0]; // 每个面由2个三角形组成,每个三角形占3个索引,所以count为6 for (let i = targetGroup.start; i < targetGroup.start + targetGroup.count; i += 3) { // 获取当前三角形的三个顶点索引 const idx1 = index.getX(i); const idx2 = index.getX(i + 1); const idx3 = index.getX(i + 2); // 通过顶点索引获取坐标 const v1 = new THREE.Vector3().fromBufferAttribute(position, idx1); const v2 = new THREE.Vector3().fromBufferAttribute(position, idx2); const v3 = new THREE.Vector3().fromBufferAttribute(position, idx3); // 创建三角形轮廓的几何体(v1->v2->v3->v1) const lineGeo = new THREE.BufferGeometry(); const positions = new Float32Array([ v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z, v1.x, v1.y, v1.z ]); lineGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3)); const lineMat = new THREE.LineBasicMaterial({ color: 'white' }); const lineMesh = new THREE.LineLoop(lineGeo, lineMat); // 使用LineLoop自动闭合轮廓 scene.add(lineMesh); }
4. 额外说明
- 使用
THREE.LineLoop可以自动实现轮廓闭合,无需手动重复第一个顶点 - 如果需要获取面的所有顶点并去重(得到面的四个顶点),可以将每个三角形的顶点存入Set,再取出即可得到单个面的四个唯一顶点
内容的提问来源于stack exchange,提问作者MiguelG
相关产品推荐
相关产品推荐

