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'; : 'NOT_INTERSECTED';
} }
// ─── Local frustum construction ────────────────────────────────────────────── //world-space to an object's local space
/**
* Transform a world-space CircularFrustum into an object's local space.
* Note: halfAngle is only preserved exactly under uniform scale.
*/
private toObjectLocalSpace(invWorldMatrix: THREE.Matrix4): CircularFrustum { private toObjectLocalSpace(invWorldMatrix: THREE.Matrix4): CircularFrustum {
return this.frustum.transform(invWorldMatrix); return this.frustum.transform(invWorldMatrix);
} }
@ -140,6 +135,8 @@ export class CircularFrustumIntersection {
if (this.insersectsSphere(boundingSphere) === 'NOT_INTERSECTED') if (this.insersectsSphere(boundingSphere) === 'NOT_INTERSECTED')
return []; return [];
const axisRay = new THREE.Ray(localFrustum.apex, localFrustum.axisNormalized);
const results: HitResult[] = []; const results: HitResult[] = [];
if (!geometry.boundsTree) if (!geometry.boundsTree)
@ -208,12 +205,19 @@ export class CircularFrustumIntersection {
tryPoint(a.clone().addScaledVector(edge, tApex)); 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(); const closestOnFace = new THREE.Vector3();
tri.closestPointToPoint(localFrustum.apex, closestOnFace); threeTri.closestPointToPoint(localFrustum.apex, closestOnFace);
if (!isNaN(closestOnFace.x)) if (!isNaN(closestOnFace.x))
tryPoint(closestOnFace); 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) { if (bestLocal !== undefined) {
const worldPoint = (bestLocal as THREE.Vector3).clone().applyMatrix4(mesh.matrixWorld); const worldPoint = (bestLocal as THREE.Vector3).clone().applyMatrix4(mesh.matrixWorld);
const worldDepth = worldFrustum.axisNormalized.dot(worldPoint.clone().sub(worldFrustum.apex)); const worldDepth = worldFrustum.axisNormalized.dot(worldPoint.clone().sub(worldFrustum.apex));