You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测两个非索引BufferGeometry不同面的相交情况?

我来帮你解决这个问题,你遇到的情况其实是Raycaster在处理自身几何体和非索引面时的几个常见坑,咱们一步步来梳理解决方案:

问题根源分析

你的代码思路没问题,但有两个关键问题导致Raycaster没起作用:

  1. 射线起点刚好在当前面上,Raycaster会因为深度测试精度问题忽略这个面,同时如果法线向外,射线根本射不到几何体内部的其他面;
  2. 检测自身Mesh时,默认可能会返回当前发射射线的面,需要手动过滤。
解决方案1:修复Raycaster检测逻辑

调整射线起点和方向,再过滤当前面,就能正确检测到非索引几何体的面相交:

var box = new THREE.Mesh(geometry.toNonIndexed(), material);
var raycaster = new THREE.Raycaster();
var intersects = [];
var pos = box.geometry.attributes.position;
var ori = new THREE.Vector3();
var dir = new THREE.Vector3();
var a = new THREE.Vector3(), b = new THREE.Vector3(), c = new THREE.Vector3(), tri = new THREE.Triangle();
var faces = pos.count / 3;

for (let i = 0; i < faces; i++) {
    a.fromBufferAttribute(pos, i * 3 + 0);
    b.fromBufferAttribute(pos, i * 3 + 1);
    c.fromBufferAttribute(pos, i * 3 + 2);
    tri.set(a, b, c);
    tri.getMidpoint(ori);
    tri.getNormal(dir);
    
    // 关键1:反转法线方向,让射线射向几何体内部(如果检测内部相交)
    dir.negate();
    // 关键2:微小偏移起点,避免射线起点与当前面重合,解决精度问题
    ori.add(dir.multiplyScalar(0.001));
    
    raycaster.set(ori, dir);
    intersects = raycaster.intersectObject(box, true);
    
    // 过滤掉当前发射射线的面,只保留其他面的相交结果
    const validIntersects = intersects.filter(intersect => intersect.faceIndex !== i);
    
    if (validIntersects.length > 0) {
        console.log(`面 ${i} 与面 ${validIntersects[0].faceIndex} 相交`, validIntersects[0]);
    }
}
解决方案2:直接检测三角面相交(更可靠,适合面数少的场景)

如果你的几何体面数不多,可以跳过Raycaster,直接用Three.js的Triangle.intersectsTriangle方法检测两两三角面是否相交,这种方式更直接,没有射线检测的精度问题:

var box = new THREE.Mesh(geometry.toNonIndexed(), material);
var pos = box.geometry.attributes.position;
var tri1 = new THREE.Triangle();
var tri2 = new THREE.Triangle();
var a1 = new THREE.Vector3(), b1 = new THREE.Vector3(), c1 = new THREE.Vector3();
var a2 = new THREE.Vector3(), b2 = new THREE.Vector3(), c2 = new THREE.Vector3();
var faces = pos.count / 3;

// 遍历所有两两不同的面组合,避免重复检测
for (let i = 0; i < faces; i++) {
    a1.fromBufferAttribute(pos, i * 3 + 0);
    b1.fromBufferAttribute(pos, i * 3 + 1);
    c1.fromBufferAttribute(pos, i * 3 + 2);
    tri1.set(a1, b1, c1);
    
    for (let j = i + 1; j < faces; j++) {
        a2.fromBufferAttribute(pos, j * 3 + 0);
        b2.fromBufferAttribute(pos, j * 3 + 1);
        c2.fromBufferAttribute(pos, j * 3 + 2);
        tri2.set(a2, b2, c2);
        
        if (tri1.intersectsTriangle(tri2)) {
            console.log(`面 ${i} 与面 ${j} 相交`);
        }
    }
}
方案选择建议
  • 如果你的几何体面数较少(几百面以内),优先选三角面直接检测,逻辑简单且精度高;
  • 如果面数较多(上千面),选Raycaster方案,时间复杂度更低,效率更高。

内容的提问来源于stack exchange,提问作者vinkovsky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:09:42