import { Vec2 } from '../../math/Vec2'; import { Vec3 } from '../../math/Vec3'; import { CameraRenderer } from '../../core/renderers/utils'; import { Camera } from '../../core/cameras/Camera'; import { GPUCurtains } from '../../curtains/GPUCurtains'; import { ProjectedMesh } from '../../core/renderers/GPURenderer'; import { IndexBuffer } from '../../core/geometries/IndexedGeometry'; import { VertexBufferAttribute } from '../../types/Geometries'; import { Object3D } from '../../core/objects3D/Object3D'; /** * Defines the returned values when an intersection between the {@link Raycaster#ray | ray} and a {@link ProjectedMesh | projected mesh} has been found. */ export interface Intersection { /** Intersected {@link ProjectedMesh | projected mesh}. */ object: ProjectedMesh; /** Distance from the {@link Raycaster#ray | ray} origin to the intersection point. */ distance: number; /** {@link Vec3 | Coordinate} of the intersection point in {@link object} local space. */ localPoint: Vec3; /** {@link Vec3 | Coordinate} of the intersection point in world space. */ point: Vec3; /** The triangle (as an array of {@link Vec3} vertices) inside which lies the intersection point. */ triangle: Vec3[]; /** Index of the triangle in the {@link ProjectedMesh | projected mesh} geometry position or index array. */ triangleIndex: number; /** Interpolated {@link Vec2 | uv coordinates} of the intersection point. */ uv?: Vec2; /** Interpolated {@link Vec3 | normal} of the intersection point, in {@link object} local space. */ normal?: Vec3; } /** * Utility to help with raycasting (determining what objects in the 3d space the mouse is over). * * @example * ```javascript * // set our main GPUCurtains instance * const gpuCurtains = new GPUCurtains({ * container: '#canvas' // selector of our WebGPU canvas container * }) * * // set the GPU device * // note this is asynchronous * await gpuCurtains.setDevice() * * // create a mesh with a box geometry * // will use the normals colors as default shading * const mesh = new Mesh(gpuCurtains, { * label: 'My mesh', * geometry: new BoxGeometry(), * }) * * const raycaster = new Raycaster(gpuCurtains) * * window.addEventListener('mousemove', (e) => { * raycaster.setFromMouse(e) * * const intersections = raycaster.intersectObject(mesh) * * if(intersections.length) { * // the mouse is hovering the mesh * mesh.scale.set(1.25) * } else { * // the mouse is not hovering the mesh * mesh.scale.set(1) * } * }) * ``` */ export declare class Raycaster { #private; /** The type of the {@link Raycaster}. */ type: string; /** The {@link CameraRenderer} used. */ renderer: CameraRenderer; /** The {@link Camera} used. */ camera: Camera | null; /** Pointer position in normalized device coordinates (in the [-1, 1] range). */ pointer: Vec2; /** Ray used to test for intersections. */ ray: { /** Origin of the ray in world space ({@link Camera} position). */ origin: Vec3; /** Normalized direction of the ray in world space. */ direction: Vec3; }; /** * Raycaster constructor * @param renderer - {@link CameraRenderer} object or {@link GPUCurtains} class object used to create this {@link Raycaster} */ constructor(renderer: CameraRenderer | GPUCurtains); /** * Set or reset this {@link Raycaster} {@link Raycaster.renderer | renderer}. * @param renderer - New {@link CameraRenderer} or {@link GPUCurtains} instance to use. */ setRenderer(renderer: CameraRenderer | GPUCurtains): void; /** * Set the {@link pointer} normalized device coordinates values (in the [-1, 1] range) based on a mouse/pointer/touch event and the {@link CameraRenderer#boundingRect | renderer bounding rectangle}. Useful if the canvas has a fixed position for example, but you might need to directly use {@link setFromNDCCoords} if not. * @param e - Mouse, pointer or touch event. */ setFromMouse(e: MouseEvent | PointerEvent | TouchEvent): void; /** * Set the {@link pointer} normalized device coordinates (in the [-1, 1] range). * @param x - input position along the X axis in the [-1, 1] range where `-1` represents the left edge and `1` the right edge. * @param y - input position along the Y axis in the [-1, 1] range where `-1` represents the bottom edge and `1` the top edge. */ setFromNDCCoords(x?: number, y?: number): void; /** * Sets the {@link ray} origin and direction based on the {@link camera} and the normalized device coordinates of the {@link pointer}. */ setRay(): void; /** * Ray-Triangle Intersection with Möller–Trumbore Algorithm. * @param intersectionPoint - {@link Vec3} to store the intersection point if any. * @returns - Whether an intersection point has been found or not. */ rayIntersectsTriangle(intersectionPoint: Vec3): boolean; /** * Find the barycentric contributions of a given intersection point lying inside our current triangle. * @param intersectionPoint - Given {@link Vec3 | intersection point}. * @returns - {@link Vec3} barycentric contributions. */ getBarycentricCoordinates(intersectionPoint: Vec3): Vec3; /** * Get a rough estimation of the current normal of our current triangle, in local space. * @returns - {@link Vec3} normal. */ getTriangleNormal(): Vec3; /** * Set our input vector with the desired attribute value at the given offset defined by our triangleIndex, offset and whether we're using and indexed geometry or not. * @param triangleIndex - Index of the triangle for which to look our attribute value. * @param offset - Index of the point inside our triangle (`0`, `1` or `2`). * @param indices - Indexed geometry array if defined or `null`. * @param attribute - {@link VertexBufferAttribute | Vertex buffer attribute} to get the value from. * @param vector - Input vector to set (can either be a {@link Vec2} or {@link Vec3}). */ setAttributeVectorAtIndex(triangleIndex: number, offset: number, indices: IndexBuffer['array'] | null, attribute: VertexBufferAttribute, vector: Vec2 | Vec3): void; /** * Test whether the {@link ray} is intersecting a given object, if the is object is actually a {@link ProjectedMesh | projected mesh}. * Then, if the recursive flag is set to `true`, test if the {@link Object3D#children | object's children} are intersecting as well. * @param object - {@link Object3D | object} to test against. * @param recursive - Whether we should also test against the {@link Object3D#children | object's children}. Default to `true`. * @param intersections - Already existing {@link Intersection | intersections} if any. * @returns - Updated {@link Intersection | intersections}. */ intersectObject(object: Object3D, recursive?: boolean, intersections?: Intersection[]): Intersection[]; /** * Test whether the {@link ray} is intersecting a given array of objects. * If the recursive flag is set to `true`, test if each {@link Object3D#children | object's children} are intersecting as well. * @param objects - Array of {@link Object3D | objects} to test against. * @param recursive - Whether we should also test against each {@link Object3D#children | object's children}. Default to `true`. * @param intersections - Already existing {@link Intersection | intersections} if any. * @returns - Updated {@link Intersection | intersections}. */ intersectObjects(objects: Object3D[], recursive?: boolean, intersections?: Intersection[]): Intersection[]; }