File size: 1,741 Bytes
352fb85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
45
46
47
48
49
50
51
52
53
54
55
56
57
import { Box3 } from "./Box3";

class BVHNode {
    public left: BVHNode | null = null;
    public right: BVHNode | null = null;
    public pointIndices: number[] = [];

    constructor(
        public bounds: Box3,
        public boxes: Box3[],
        pointIndices: number[],
    ) {
        if (pointIndices.length > 1) {
            this.split(bounds, boxes, pointIndices);
        } else if (pointIndices.length > 0) {
            this.pointIndices = pointIndices;
        }
    }

    private split(bounds: Box3, boxes: Box3[], pointIndices: number[]) {
        const axis = bounds.size().maxComponent();
        pointIndices.sort((a, b) => boxes[a].center().getComponent(axis) - boxes[b].center().getComponent(axis));

        const mid = Math.floor(pointIndices.length / 2);
        const leftIndices = pointIndices.slice(0, mid);
        const rightIndices = pointIndices.slice(mid);

        this.left = new BVHNode(bounds, boxes, leftIndices);
        this.right = new BVHNode(bounds, boxes, rightIndices);
    }

    public queryRange(range: Box3): number[] {
        if (!this.bounds.intersects(range)) {
            return [];
        } else if (this.left !== null && this.right !== null) {
            return this.left.queryRange(range).concat(this.right.queryRange(range));
        } else {
            return this.pointIndices.filter((index) => range.intersects(this.boxes[index]));
        }
    }
}

class BVH {
    public root: BVHNode;

    constructor(bounds: Box3, boxes: Box3[]) {
        const pointIndices = boxes.map((_, index) => index);
        this.root = new BVHNode(bounds, boxes, pointIndices);
    }

    public queryRange(range: Box3) {
        return this.root.queryRange(range);
    }
}

export { BVH };