All files / src/components/VirtualWalkthrough xr-ray-quad.ts

100% Statements 15/15
100% Branches 10/10
100% Functions 1/1
100% Lines 15/15

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44                          2x                 7x 7x 7x 7x 1x     6x 6x 1x     5x 5x 5x 5x 1x     4x    
import { Vec3 } from 'playcanvas';
 
export interface QuadHit {
  u: number;
  v: number;
}
 
/**
 * Intersects the ray with the rectangle centred at `center` and spanned by unit axes `right`/`up`,
 * returning the hit in normalized quad coordinates (u,v in [-1,1]) or null. `u`/`v` divide the
 * in-plane offset by `halfWidth`/`halfHeight`. Null when the ray is parallel to the plane, the
 * plane is behind the origin, or the hit lands outside the rectangle.
 */
export const rayQuadHit = (
  origin: Vec3,
  direction: Vec3,
  center: Vec3,
  right: Vec3,
  up: Vec3,
  halfWidth: number,
  halfHeight: number
): QuadHit | null => {
  const dir = direction.clone().normalize();
  const normal = new Vec3().cross(right, up);
  const denom = dir.dot(normal);
  if (Math.abs(denom) < 1e-6) {
    return null;
  }
 
  const t = new Vec3().sub2(center, origin).dot(normal) / denom;
  if (t < 0) {
    return null;
  }
 
  const offset = new Vec3().copy(dir).mulScalar(t).add(origin).sub(center);
  const u = offset.dot(right) / halfWidth;
  const v = offset.dot(up) / halfHeight;
  if (u < -1 || u > 1 || v < -1 || v > 1) {
    return null;
  }
 
  return { u, v };
};