fixed hit test on large faces

This commit is contained in:
azykov@mail.ru 2026-05-23 09:21:53 +03:00
parent cf45752848
commit 7d3b8ca232
No known key found for this signature in database
1 changed files with 12 additions and 8 deletions

View File

@ -110,12 +110,7 @@ export class CircularFrustumIntersection {
: 'NOT_INTERSECTED';
}
// ─── Local frustum construction ──────────────────────────────────────────────
/**
* Transform a world-space CircularFrustum into an object's local space.
* Note: halfAngle is only preserved exactly under uniform scale.
*/
//world-space to an object's local space
private toObjectLocalSpace(invWorldMatrix: THREE.Matrix4): CircularFrustum {
return this.frustum.transform(invWorldMatrix);
}
@ -140,6 +135,8 @@ export class CircularFrustumIntersection {
if (this.insersectsSphere(boundingSphere) === 'NOT_INTERSECTED')
return [];
const axisRay = new THREE.Ray(localFrustum.apex, localFrustum.axisNormalized);
const results: HitResult[] = [];
if (!geometry.boundsTree)
@ -208,12 +205,19 @@ export class CircularFrustumIntersection {
tryPoint(a.clone().addScaledVector(edge, tApex));
}
// 3. Closest point on the triangle face to the apex
// 3. Closest point on triangle face to the apex (using THREE.Triangle, not ExtendedTriangle)
const threeTri = new THREE.Triangle(tri.a, tri.b, tri.c);
const closestOnFace = new THREE.Vector3();
tri.closestPointToPoint(localFrustum.apex, closestOnFace);
threeTri.closestPointToPoint(localFrustum.apex, closestOnFace);
if (!isNaN(closestOnFace.x))
tryPoint(closestOnFace);
// 4. Axis ray through the face — catches large faces the cone passes through
const faceHit = new THREE.Vector3();
if (axisRay.intersectTriangle(tri.a, tri.b, tri.c, false, faceHit)) {
tryPoint(faceHit);
}
if (bestLocal !== undefined) {
const worldPoint = (bestLocal as THREE.Vector3).clone().applyMatrix4(mesh.matrixWorld);
const worldDepth = worldFrustum.axisNormalized.dot(worldPoint.clone().sub(worldFrustum.apex));