如何适配Three.js新版BufferGeometry实现平面与网格交点检测?
适配新版Three.js的几何体面相交检测方案
新版Three.js中BufferGeometry替代了旧版的Geometry,不再有faces和vertices属性,需要通过index和position属性来获取三角面与顶点数据,以下是修改后的代码:
// 提前声明复用的向量,避免频繁创建对象 const a = new THREE.Vector3(); const b = new THREE.Vector3(); const c = new THREE.Vector3(); const geometry = obj.geometry; const positionAttr = geometry.getAttribute('position'); const indexArray = geometry.index ? geometry.index.array : null; // 处理带索引的几何体(大部分复杂模型会用索引) if (indexArray) { // 每3个索引对应一个三角面 for (let i = 0; i < indexArray.length; i += 3) { // 获取当前三角面的三个顶点索引 const idxA = indexArray[i]; const idxB = indexArray[i + 1]; const idxC = indexArray[i + 2]; // 从position属性中读取顶点局部坐标 a.set(positionAttr.getX(idxA), positionAttr.getY(idxA), positionAttr.getZ(idxA)); b.set(positionAttr.getX(idxB), positionAttr.getY(idxB), positionAttr.getZ(idxB)); c.set(positionAttr.getX(idxC), positionAttr.getY(idxC), positionAttr.getZ(idxC)); // 转换为世界坐标 obj.localToWorld(a); obj.localToWorld(b); obj.localToWorld(c); // 创建三条边(克隆向量避免后续循环覆盖值) const lineAB = new THREE.Line3(a.clone(), b.clone()); const lineBC = new THREE.Line3(b.clone(), c.clone()); const lineCA = new THREE.Line3(c.clone(), a.clone()); // 调用交点检测方法,i/3对应原代码中的face索引 setPointOfIntersection(lineAB, mathPlane, Math.floor(i / 3)); setPointOfIntersection(lineBC, mathPlane, Math.floor(i / 3)); setPointOfIntersection(lineCA, mathPlane, Math.floor(i / 3)); } } else { // 处理不带索引的几何体(简单几何体可能会用这种方式) const vertexCount = positionAttr.count; // 每3个顶点对应一个三角面 for (let i = 0; i < vertexCount; i += 3) { // 读取三个顶点的局部坐标 a.set(positionAttr.getX(i), positionAttr.getY(i), positionAttr.getZ(i)); b.set(positionAttr.getX(i + 1), positionAttr.getY(i + 1), positionAttr.getZ(i + 1)); c.set(positionAttr.getX(i + 2), positionAttr.getY(i + 2), positionAttr.getZ(i + 2)); // 转换为世界坐标 obj.localToWorld(a); obj.localToWorld(b); obj.localToWorld(c); // 创建三条边 const lineAB = new THREE.Line3(a.clone(), b.clone()); const lineBC = new THREE.Line3(b.clone(), c.clone()); const lineCA = new THREE.Line3(c.clone(), a.clone()); // 调用交点检测方法 setPointOfIntersection(lineAB, mathPlane, Math.floor(i / 3)); setPointOfIntersection(lineBC, mathPlane, Math.floor(i / 3)); setPointOfIntersection(lineCA, mathPlane, Math.floor(i / 3)); } }
关键变化说明
- 顶点数据获取:通过
geometry.getAttribute('position')拿到顶点属性,用getX/Y/Z(index)方法读取指定顶点的坐标;也可以直接访问positionAttr.array(比如positionAttr.array[idxA * 3]取x值,idxA*3+1取y,idxA*3+2取z),两种方式效果一致。 - 三角面索引:带索引的几何体通过
geometry.index.array获取每个三角面的顶点索引,每3个元素对应一个面;无索引的几何体直接按顺序每3个顶点组成一个面。 - 向量复用:提前声明
a/b/c三个向量,避免在循环中频繁创建对象提升性能;创建Line3时克隆向量,防止后续循环修改原向量导致边的坐标被覆盖。
内容的提问来源于stack exchange,提问作者Kang Gilar
相关产品推荐
相关产品推荐

