在Three.js中计算立方体与平面的相交情况
THREE.js 平面与变换后立方体的相交判断及相交信息获取
一、判断是否相交
核心思路是将世界空间的平面转换到立方体局部坐标系,简化单位立方体的相交判断:
- 获取立方体的世界变换矩阵:若使用
THREE.Mesh,取mesh.matrixWorld;若直接操作几何体,取geometry.matrix。 - 计算变换矩阵的逆矩阵:
const inverseMatrix = new THREE.Matrix4().getInverse(mesh.matrixWorld); - 将世界平面转换到立方体局部坐标系:
const localPlane = plane.clone().applyMatrix4(inverseMatrix); - 定义单位立方体的8个局部顶点(
THREE.BoxGeometry(1,1,1)的顶点范围是±0.5):const localVertices = [ new THREE.Vector3(-0.5, -0.5, -0.5), new THREE.Vector3(0.5, -0.5, -0.5), new THREE.Vector3(0.5, 0.5, -0.5), new THREE.Vector3(-0.5, 0.5, -0.5), new THREE.Vector3(-0.5, -0.5, 0.5), new THREE.Vector3(0.5, -0.5, 0.5), new THREE.Vector3(0.5, 0.5, 0.5), new THREE.Vector3(-0.5, 0.5, 0.5) ]; - 遍历顶点计算平面距离的符号:
let hasPositive = false; let hasNegative = false; let hasZero = false; const eps = 1e-6; for (const v of localVertices) { const dist = localPlane.distanceToPoint(v); if (dist > eps) hasPositive = true; else if (dist < -eps) hasNegative = true; else hasZero = true; } - 相交判定:
- 若
hasPositive && hasNegative:必然相交; - 若
hasZero && !(hasPositive || hasNegative):平面包含立方体的部分顶点/棱/面,属于相交; - 其余情况:不相交。
- 若
二、确定相交形态
基于局部坐标系下的交点数量和连接关系判断:
- 退化形态:
- 点:仅1个交点(平面切中立方体顶点,其余顶点全在同侧);
- 线段:仅2个交点(平面切过一条棱,或与两个平行面各交一条棱);
- 非退化形态:
- 三角形:3个交点,平面与立方体3个面相交;
- 平行四边形:4个交点,平面与立方体4个两两平行的面相交;
- 六边形:6个交点,平面与立方体6个面各交一条棱。
三、获取相交顶点坐标
2.1 立方体自身参考系(局部坐标系)坐标
- 定义立方体的12条棱:
const edges = [ [0,1], [1,2], [2,3], [3,0], [4,5], [5,6], [6,7], [7,4], [0,4], [1,5], [2,6], [3,7] ]; - 遍历棱计算交点:
const localIntersects = []; const eps = 1e-6; for (const [i1, i2] of edges) { const v1 = localVertices[i1]; const v2 = localVertices[i2]; const d1 = localPlane.distanceToPoint(v1); const d2 = localPlane.distanceToPoint(v2); // 两点在平面两侧,计算交点 if (d1 * d2 < -eps) { const t = Math.abs(d1) / (Math.abs(d1) + Math.abs(d2)); const intersect = v1.clone().lerp(v2, t); localIntersects.push(intersect); } // 顶点在平面上,去重后加入 else if (Math.abs(d1) <= eps) { if (!localIntersects.some(p => p.distanceToSquared(v1) <= eps * eps)) { localIntersects.push(v1.clone()); } } else if (Math.abs(d2) <= eps) { if (!localIntersects.some(p => p.distanceToSquared(v2) <= eps * eps)) { localIntersects.push(v2.clone()); } } } - 对交点排序(可选,用于得到有序的截面轮廓):
将交点投影到平面内的二维坐标系,按极角排序即可。
2.2 标准参考系(世界坐标系)坐标
将局部交点通过立方体的世界变换矩阵转换:
const worldIntersects = localIntersects.map(p => p.clone().applyMatrix4(mesh.matrixWorld));
内容的提问来源于stack exchange,提问作者Mathieu CAROFF
相关产品推荐
相关产品推荐

