Files
healer-man/src/scene/dungeonLabelVisibility.ts
T
2026-09-09 22:18:15 -04:00

37 lines
1.1 KiB
TypeScript

import type { Ray, Vector, World } from "@dimforge/rapier3d-compat";
import { interactionGroups } from "@react-three/rapier";
interface LabelRapierApi {
readonly Ray: new (origin: Vector, direction: Vector) => Ray;
readonly QueryFilterFlags: {
readonly ONLY_FIXED: number;
readonly EXCLUDE_SENSORS: number;
};
}
const LABEL_OCCLUSION_GROUPS = interactionGroups(0, 0);
const LABEL_SURFACE_MARGIN = 0.08;
/** Uses Rapier's spatial index, bounded to the camera-to-label segment. */
export function hasDungeonLabelLineOfSight(
rapier: LabelRapierApi,
world: World,
camera: Vector,
label: Vector,
): boolean {
const dx = label.x - camera.x;
const dy = label.y - camera.y;
const dz = label.z - camera.z;
const distance = Math.hypot(dx, dy, dz);
if (!Number.isFinite(distance)) return false;
if (distance <= LABEL_SURFACE_MARGIN) return true;
const ray = new rapier.Ray(camera, { x: dx / distance, y: dy / distance, z: dz / distance });
return !world.castRay(
ray,
distance - LABEL_SURFACE_MARGIN,
true,
rapier.QueryFilterFlags.ONLY_FIXED | rapier.QueryFilterFlags.EXCLUDE_SENSORS,
LABEL_OCCLUSION_GROUPS,
);
}