# PointsBVH

class in `three-mesh-bvh`, extends `GeometryBVH`

```js
import { PointsBVH } from 'three-mesh-bvh';
```

BVH for `THREE.Points` geometries. Each BVH primitive represents a single point.

Example: Casting rays at two million points every frame

```js
import { BufferAttribute, BufferGeometry, LineBasicMaterial, LineSegments, Points, PointsMaterial, Raycaster, Vector3 } from 'three';
import { PLYLoader } from 'three/addons/loaders/PLYLoader.js';
import { computeBoundsTree, acceleratedRaycast, PointsBVH } from 'three-mesh-bvh';

// scene, camera and renderer are initialized here

const URL = 'https://raw.githubusercontent.com/gkjohnson/3d-demo-data/main/models/point-cloud-porsche/scene.ply';
const RAYS = 500;
const UP = new Vector3( 0, 1, 0 );

BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
Points.prototype.raycast = acceleratedRaycast;

const geometry = await new PLYLoader().loadAsync( URL );
geometry.computeBoundsTree( { type: PointsBVH } );

const cloud = new Points( geometry, new PointsMaterial( { size: 0.005, vertexColors: true } ) );
cloud.position.set( - 0.52, 0.59, 2.82 );
scene.add( cloud );
camera.position.set( 5, 5, 10 );

const origins = new Array( RAYS ).fill().map( () => new Vector3().randomDirection().multiplyScalar( 4 ) );
const rays = new BufferGeometry();
rays.setAttribute( 'position', new BufferAttribute( new Float32Array( RAYS * 6 ), 3 ) );
scene.add(
	new LineSegments( rays, new LineBasicMaterial( { color: 0xe91e63, transparent: true, opacity: 0.25 } ) ),
	new Points( rays, new PointsMaterial( { color: 0xe91e63, size: 0.04 } ) ),
);

const raycaster = new Raycaster();
raycaster.firstHitOnly = true;
raycaster.params.Points.threshold = 0.01;
const { ray } = raycaster;
const hits = [];
renderer.setAnimationLoop( time => {

	const position = rays.attributes.position;
	for ( let i = 0; i < RAYS; i ++ ) {

		ray.origin.copy( origins[ i ] ).applyAxisAngle( UP, time * 0.00006 );
		ray.direction.copy( ray.origin ).negate().normalize();
		hits.length = 0;
		raycaster.intersectObject( cloud, false, hits );
		const end = hits.length ? hits[ 0 ].point : ray.origin;
		position.setXYZ( 2 * i, ray.origin.x, ray.origin.y, ray.origin.z );
		position.setXYZ( 2 * i + 1, end.x, end.y, end.z );

	}

	position.needsUpdate = true;
	renderer.render( scene, camera );

} );
```

## Methods

### .shapecast

```js
.shapecast( callbacks: Object ): boolean
```

Performs a spatial query against the BVH. Extends the base `shapecast` with an
`intersectsPoint` callback that is called once per point primitive in leaf nodes.

- `callbacks`, `Object`
  - `intersectsBounds`, `IntersectsBoundsCallback`
  - `intersectsPoint`, `IntersectsPointCallback`, optional
  - `intersectsRange`, `IntersectsRangeCallback`, optional
  - `boundsTraverseOrder`, `BoundsTraverseOrderCallback`, optional
