@woosh/meep-engine 2.67.0 → 2.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/bundle-worker-terrain.js +1 -1
- package/build/meep.cjs +698 -1270
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +698 -1270
- package/package.json +1 -1
- package/src/core/bvh2/binary/2/BinaryUint32BVH.js +55 -28
- package/src/core/bvh2/binary/2/BinaryUint32BVH.spec.js +3 -3
- package/src/core/bvh2/binary/2/bvh32_query_user_data_overlaps_clipping_volume.js +94 -0
- package/src/core/bvh2/binary/2/bvh32_query_user_data_ray.js +17 -18
- package/src/core/bvh2/bvh3/query/BVHQueryIntersectsFrustum.js +4 -2
- package/src/core/geom/3d/aabb/AABB3.js +14 -14
- package/src/core/geom/3d/aabb/aabb3_array_intersects_clipping_volume_array.js +30 -0
- package/src/core/geom/3d/aabb/aabb3_intersects_clipping_volume_array.js +51 -0
- package/src/core/geom/3d/frustum/{read_frustum_planes_to_array.js → read_three_planes_to_array.js} +5 -3
- package/src/core/geom/3d/triangle/triangle_intersects_clipping_volume.js +51 -0
- package/src/engine/ecs/terrain/ecs/TerrainSystem.js +2 -2
- package/src/engine/ecs/terrain/ecs/makeTerrainWorkerProxy.js +1 -1
- package/src/engine/ecs/terrain/tiles/TerrainTile.js +9 -46
- package/src/engine/graphics/ecs/mesh/Mesh.d.ts +0 -1
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +0 -5
- package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +0 -1
- package/src/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.d.ts +2 -2
- package/src/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.js +79 -36
- package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_overlap_clipping_volume.js +88 -0
- package/src/engine/graphics/geometry/buffered/query/bvh32_geometry_raycast.js +108 -0
- package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_indexed_geometry.js +4 -30
- package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_unindexed_geometry.js +30 -0
- package/src/engine/graphics/geometry/bvh/buffered/bvh32_set_leaf_from_triangle.js +41 -0
- package/src/engine/graphics/material/optimization/prototypeMaterialOptimizer.js +16 -19
- package/src/engine/graphics/render/forward_plus/LightManager.js +2 -2
- package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +46 -47
- package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +2 -2
- package/src/engine/graphics/render/view/CameraView.js +8 -8
- package/src/core/bvh2/BVHTasks.js +0 -65
- package/src/core/bvh2/BinaryNode.d.ts +0 -13
- package/src/core/bvh2/BinaryNode.js +0 -1188
- package/src/core/bvh2/BinaryNode.spec.js +0 -309
- package/src/core/bvh2/LeafNode.d.ts +0 -7
- package/src/core/bvh2/LeafNode.js +0 -147
- package/src/core/bvh2/Node.d.ts +0 -9
- package/src/core/bvh2/Node.js +0 -196
- package/src/core/bvh2/NodeValidator.js +0 -197
- package/src/core/bvh2/StacklessTraverser.js +0 -154
- package/src/core/bvh2/StacklessTraverser.spec.js +0 -109
- package/src/core/bvh2/binary/BinaryBVH.js +0 -281
- package/src/core/bvh2/binary/IndexedBinaryBVH.js +0 -407
- package/src/core/bvh2/binary/IndexedBinaryBVH.spec.js +0 -27
- package/src/core/bvh2/binary/IndexedBinaryBVHVisitor.js +0 -11
- package/src/core/bvh2/binary/NodeType.js +0 -8
- package/src/core/bvh2/binary/RayLeafIntersectionVisitor.js +0 -59
- package/src/core/bvh2/serialization/deserializeBinaryNode.js +0 -40
- package/src/core/bvh2/serialization/deserializeBinaryNodeFromBinaryBuffer.js +0 -90
- package/src/core/bvh2/serialization/serializeBinaryNode.js +0 -31
- package/src/core/bvh2/serialization/serializeBinaryNodeToBinaryBuffer.js +0 -86
- package/src/core/bvh2/transform/BottomUpOptimizingRebuilder.js +0 -144
- package/src/core/bvh2/transform/RotationOptimizer.js +0 -123
- package/src/core/bvh2/transform/RotationOptimizer.spec.js +0 -303
- package/src/core/bvh2/transform/tryRotateSingleNode.js +0 -260
- package/src/core/bvh2/traversal/BVHVisitor.js +0 -30
- package/src/core/bvh2/traversal/RaycastBVHVisitor.js +0 -66
- package/src/core/bvh2/traversal/ThreeClippingPlaneComputingBVHVisitor.js +0 -384
- package/src/core/bvh2/traversal/ThreeFrustumsIntersectionBVHVisitor.js +0 -52
- package/src/core/bvh2/traversal/bvh_traverse_pre_order_using_stack.js +0 -43
- package/src/core/bvh2/traversal/queryBinaryNode_ClippingPlanes.d.ts +0 -5
- package/src/core/bvh2/traversal/queryBinaryNode_ClippingPlanes.js +0 -66
- package/src/core/bvh2/traversal/queryBinaryNode_CollectData.js +0 -49
- package/src/core/bvh2/traversal/queryBinaryNode_CollectLeaves.js +0 -51
- package/src/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +0 -77
- package/src/core/bvh2/traversal/queryBinaryNode_SphereIntersections.js +0 -63
- package/src/core/bvh2/traversal/traverseBinaryNodeUsingVisitor.js +0 -50
- package/src/core/bvh2/traversal/traverseBinaryNodeUsingVisitor_DepthFirst_PreOrder.js +0 -34
- package/src/core/bvh2/util/find_least_common_ancestor.js +0 -34
- package/src/core/bvh2/visual/convert_bvh_to_dot_format_string.js +0 -50
- package/src/core/geom/2d/bvh/BinaryNode2.js +0 -152
- package/src/core/geom/2d/bvh/LeafNode2.js +0 -11
- package/src/core/geom/2d/bvh/Node2.js +0 -51
- package/src/core/geom/3d/aabb/aabb3_array_intersects_frustum_array.js +0 -20
- package/src/core/geom/3d/aabb/aabb3_intersects_frustum_array.js +0 -35
- package/src/engine/ecs/terrain/tiles/FirstRayIntersectionTerrainBVHVisitor.js +0 -74
- package/src/engine/graphics/geometry/buffered/query/ClippingPlaneContainmentComputingVisitor.js +0 -195
- package/src/engine/graphics/geometry/buffered/query/GeometryVisitor.js +0 -87
- package/src/engine/graphics/geometry/buffered/query/RaycastNearestHitComputingVisitor.js +0 -206
- package/src/engine/graphics/geometry/bvh/BVHFromGeometry.js +0 -72
- package/src/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +0 -240
- package/src/engine/graphics/geometry/bvh/buffered/BinaryBVHFromBufferGeometry.js +0 -123
- package/src/engine/graphics/geometry/bvh/buffered/IndexedTraingleBoundsComputer.js +0 -43
- package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_objects.js +0 -133
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { noop } from "../../function/Functions.js";
|
|
2
|
-
import { IndexedBinaryBVHVisitor } from "./IndexedBinaryBVHVisitor.js";
|
|
3
|
-
import { NodeType } from "./NodeType.js";
|
|
4
|
-
import { aabb3_intersects_ray } from "../../geom/3d/aabb/aabb3_intersects_ray.js";
|
|
5
|
-
|
|
6
|
-
export class RayLeafIntersectionVisitor extends IndexedBinaryBVHVisitor {
|
|
7
|
-
constructor() {
|
|
8
|
-
super();
|
|
9
|
-
this.callback = noop;
|
|
10
|
-
this.callbackThisArg = null;
|
|
11
|
-
|
|
12
|
-
this.originX = 0;
|
|
13
|
-
this.originY = 0;
|
|
14
|
-
this.originZ = 0;
|
|
15
|
-
|
|
16
|
-
this.directionX = 0;
|
|
17
|
-
this.directionY = 0;
|
|
18
|
-
this.directionZ = 0;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
* @type {IndexedBinaryBVH}
|
|
23
|
-
*/
|
|
24
|
-
this.root = null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
visit(address, type) {
|
|
28
|
-
const root = this.root;
|
|
29
|
-
|
|
30
|
-
const data = root.data;
|
|
31
|
-
const binaryNodeCount = root.binaryNodeCount;
|
|
32
|
-
|
|
33
|
-
const x0 = data[address];
|
|
34
|
-
const y0 = data[address + 1];
|
|
35
|
-
const z0 = data[address + 2];
|
|
36
|
-
const x1 = data[address + 3];
|
|
37
|
-
const y1 = data[address + 4];
|
|
38
|
-
const z1 = data[address + 5];
|
|
39
|
-
|
|
40
|
-
const intersectionFound = aabb3_intersects_ray(x0, y0, z0, x1, y1, z1,
|
|
41
|
-
this.originX, this.originY, this.originZ,
|
|
42
|
-
this.directionX, this.directionY, this.directionZ
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
if (!intersectionFound) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (type === NodeType.LEAF) {
|
|
50
|
-
const value = address / 6 - binaryNodeCount;
|
|
51
|
-
|
|
52
|
-
this.callback.call(this.callbackThisArg, value, address, type);
|
|
53
|
-
|
|
54
|
-
return false;
|
|
55
|
-
} else {
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { BinaryNode } from "../BinaryNode.js";
|
|
2
|
-
import { deserializeLeafNode, LeafNode } from "../LeafNode.js";
|
|
3
|
-
import { deserializeAABB3 } from "../../geom/3d/aabb/deserializeAABB3.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
7
|
-
* @param {BinaryBuffer} buffer
|
|
8
|
-
* @param {BinaryNode} node
|
|
9
|
-
* @param {function(buffer:BinaryBuffer):void} leafValueDeserializer
|
|
10
|
-
*/
|
|
11
|
-
function deserializeBinaryNode(buffer, node, leafValueDeserializer) {
|
|
12
|
-
deserializeAABB3(buffer, node);
|
|
13
|
-
|
|
14
|
-
function deserializeChild() {
|
|
15
|
-
const nodeType = buffer.readUint8();
|
|
16
|
-
if (nodeType === 0) {
|
|
17
|
-
return null;
|
|
18
|
-
} else if (nodeType === 1) {
|
|
19
|
-
const leafNode = new LeafNode();
|
|
20
|
-
deserializeLeafNode(buffer, leafNode, leafValueDeserializer);
|
|
21
|
-
leafNode.parentNode = node;
|
|
22
|
-
return leafNode;
|
|
23
|
-
} else if (nodeType === 2) {
|
|
24
|
-
const binaryNode = new BinaryNode();
|
|
25
|
-
deserializeBinaryNode(buffer, binaryNode, leafValueDeserializer);
|
|
26
|
-
binaryNode.parentNode = node;
|
|
27
|
-
return binaryNode;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const leftNode = deserializeChild();
|
|
32
|
-
const rightNode = deserializeChild();
|
|
33
|
-
|
|
34
|
-
node.left = leftNode;
|
|
35
|
-
node.right = rightNode;
|
|
36
|
-
|
|
37
|
-
node.updateLeafNodeCount();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export { deserializeBinaryNode };
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { BinaryNode } from "../BinaryNode.js";
|
|
2
|
-
import { LeafNode } from "../LeafNode.js";
|
|
3
|
-
import { deserializeAABB3Encoded_v0 } from "../../geom/3d/aabb/deserializeAABB3Encoded_v0.js";
|
|
4
|
-
import { deserializeAABB3 } from "../../geom/3d/aabb/deserializeAABB3.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
* @param {BinaryNode} root
|
|
9
|
-
* @param {BinaryBuffer} buffer
|
|
10
|
-
* @param {function(buffer:BinaryBuffer):*} leafValueDeserializer
|
|
11
|
-
*/
|
|
12
|
-
export function deserializeBinaryNodeFromBinaryBuffer(root, buffer, leafValueDeserializer) {
|
|
13
|
-
//read bounds
|
|
14
|
-
deserializeAABB3(buffer, root);
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
* @param {BinaryNode} parent
|
|
19
|
-
* @returns {BinaryNode}
|
|
20
|
-
*/
|
|
21
|
-
function readBinaryNode(parent) {
|
|
22
|
-
|
|
23
|
-
const node = new BinaryNode();
|
|
24
|
-
|
|
25
|
-
node.parentNode = parent;
|
|
26
|
-
|
|
27
|
-
//read bounds
|
|
28
|
-
deserializeAABB3Encoded_v0(buffer, node, parent.x0, parent.y0, parent.z0, parent.x1, parent.y1, parent.z1);
|
|
29
|
-
|
|
30
|
-
//read marker
|
|
31
|
-
const marker = buffer.readUint8();
|
|
32
|
-
|
|
33
|
-
if ((marker & 3) === 3) {
|
|
34
|
-
node.left = readBinaryNode(node);
|
|
35
|
-
} else if ((marker & 2) === 2) {
|
|
36
|
-
node.left = readLeafNode(node);
|
|
37
|
-
} else {
|
|
38
|
-
node.left = null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if ((marker & 12) === 12) {
|
|
42
|
-
node.right = readBinaryNode(node);
|
|
43
|
-
} else if ((marker & 8) === 8) {
|
|
44
|
-
node.right = readLeafNode(node);
|
|
45
|
-
} else {
|
|
46
|
-
node.right = null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
node.updateLeafNodeCount();
|
|
50
|
-
|
|
51
|
-
return node;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
*
|
|
56
|
-
* @param {BinaryNode} parent
|
|
57
|
-
* @returns {LeafNode}
|
|
58
|
-
*/
|
|
59
|
-
function readLeafNode(parent) {
|
|
60
|
-
const node = new LeafNode();
|
|
61
|
-
|
|
62
|
-
node.parentNode = parent;
|
|
63
|
-
|
|
64
|
-
//read bounds
|
|
65
|
-
deserializeAABB3Encoded_v0(buffer, node, parent.x0, parent.y0, parent.z0, parent.x1, parent.y1, parent.z1);
|
|
66
|
-
|
|
67
|
-
node.object = leafValueDeserializer(buffer);
|
|
68
|
-
|
|
69
|
-
return node;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
//read marker
|
|
73
|
-
const marker = buffer.readUint8();
|
|
74
|
-
|
|
75
|
-
if ((marker & 3) === 3) {
|
|
76
|
-
root.left = readBinaryNode(root);
|
|
77
|
-
} else if ((marker & 2) === 2) {
|
|
78
|
-
root.left = readLeafNode(root);
|
|
79
|
-
} else {
|
|
80
|
-
root.left = null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if ((marker & 12) === 12) {
|
|
84
|
-
root.right = readBinaryNode(root);
|
|
85
|
-
} else if ((marker & 8) === 8) {
|
|
86
|
-
root.right = readLeafNode(root);
|
|
87
|
-
} else {
|
|
88
|
-
root.right = null;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {serializeAABB3} from "../../geom/3d/aabb/serializeAABB3.js";
|
|
2
|
-
import {isLeaf, serializeLeafNode} from "../LeafNode.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
*
|
|
6
|
-
* @param {BinaryBuffer} buffer
|
|
7
|
-
* @param {BinaryNode} node
|
|
8
|
-
* @param {function(buffer:BinaryBuffer,value:any):void} leafValueSerializer
|
|
9
|
-
*/
|
|
10
|
-
function serializeBinaryNode(buffer, node, leafValueSerializer) {
|
|
11
|
-
serializeAABB3(buffer, node);
|
|
12
|
-
|
|
13
|
-
function serializeChild(child) {
|
|
14
|
-
if (child === null) {
|
|
15
|
-
buffer.writeUint8(0);
|
|
16
|
-
} else {
|
|
17
|
-
if (isLeaf(child)) {
|
|
18
|
-
buffer.writeUint8(1);
|
|
19
|
-
serializeLeafNode(buffer, child, leafValueSerializer);
|
|
20
|
-
} else {
|
|
21
|
-
buffer.writeUint8(2);
|
|
22
|
-
serializeBinaryNode(buffer, child, leafValueSerializer);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
serializeChild(node.left);
|
|
28
|
-
serializeChild(node.right);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export {serializeBinaryNode};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { serializeAABB3 } from "../../geom/3d/aabb/serializeAABB3.js";
|
|
2
|
-
import { serializeAABB3Encoded_v0 } from "../../geom/3d/aabb/serializeAABB3Encoded_v0.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
*
|
|
6
|
-
* @param {BinaryBuffer} buffer
|
|
7
|
-
* @param {BinaryNode} node
|
|
8
|
-
* @param {BinaryNode} parent
|
|
9
|
-
* @param {function(buffer:BinaryBuffer, value:*):void} leafValueSerializer
|
|
10
|
-
*/
|
|
11
|
-
function writeBinaryNode(buffer, node, parent, leafValueSerializer) {
|
|
12
|
-
serializeAABB3Encoded_v0(buffer, node, parent.x0, parent.y0, parent.z0, parent.x1, parent.y1, parent.z1);
|
|
13
|
-
|
|
14
|
-
writeBinaryNodeContents(buffer, node, leafValueSerializer);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
*
|
|
19
|
-
* @param {BinaryBuffer} buffer
|
|
20
|
-
* @param {BinaryNode} node
|
|
21
|
-
* @param {function(buffer:BinaryBuffer, value:*):void} leafValueSerializer
|
|
22
|
-
*/
|
|
23
|
-
function writeBinaryNodeContents(buffer, node, leafValueSerializer) {
|
|
24
|
-
|
|
25
|
-
//build header marker for the node
|
|
26
|
-
let marker = 0;
|
|
27
|
-
|
|
28
|
-
const right = node.right;
|
|
29
|
-
|
|
30
|
-
if (right !== null) {
|
|
31
|
-
if (right.isLeafNode) {
|
|
32
|
-
marker |= 8;
|
|
33
|
-
} else {
|
|
34
|
-
marker |= 12;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const left = node.left;
|
|
39
|
-
|
|
40
|
-
if (left !== null) {
|
|
41
|
-
if (left.isLeafNode) {
|
|
42
|
-
marker |= 2;
|
|
43
|
-
} else {
|
|
44
|
-
marker |= 3;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
buffer.writeUint8(marker);
|
|
49
|
-
|
|
50
|
-
if ((marker & 3) === 3) {
|
|
51
|
-
writeBinaryNode(buffer, left, node, leafValueSerializer);
|
|
52
|
-
} else if ((marker & 2) === 2) {
|
|
53
|
-
writeLeafNode(buffer, left, node, leafValueSerializer);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if ((marker & 12) === 12) {
|
|
57
|
-
writeBinaryNode(buffer, right, node, leafValueSerializer);
|
|
58
|
-
} else if ((marker & 8) === 8) {
|
|
59
|
-
writeLeafNode(buffer, right, node, leafValueSerializer);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
*
|
|
65
|
-
* @param {BinaryBuffer} buffer
|
|
66
|
-
* @param {LeafNode} node
|
|
67
|
-
* @param {BinaryNode} parent
|
|
68
|
-
* @param {function(buffer:BinaryBuffer, value:*):void} leafValueSerializer
|
|
69
|
-
*/
|
|
70
|
-
function writeLeafNode(buffer, node, parent, leafValueSerializer) {
|
|
71
|
-
serializeAABB3Encoded_v0(buffer, node, parent.x0, parent.y0, parent.z0, parent.x1, parent.y1, parent.z1);
|
|
72
|
-
leafValueSerializer(buffer, node.object);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Writing is lossy, all descendants have their bounds quantized to uin16
|
|
77
|
-
* @param {BinaryNode} root
|
|
78
|
-
* @param {BinaryBuffer} buffer
|
|
79
|
-
* @param {function(buffer:BinaryBuffer, value:*):void} leafValueSerializer
|
|
80
|
-
*/
|
|
81
|
-
export function serializeBinaryNodeToBinaryBuffer(root, buffer, leafValueSerializer) {
|
|
82
|
-
//write initial size
|
|
83
|
-
serializeAABB3(buffer, root);
|
|
84
|
-
|
|
85
|
-
writeBinaryNodeContents(buffer, root, leafValueSerializer);
|
|
86
|
-
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { BinaryNode } from "../BinaryNode.js";
|
|
2
|
-
import { isLeaf } from "../LeafNode.js";
|
|
3
|
-
import { surfaceAreaHeuristic } from "../sah/surfaceAreaHeuristic.js";
|
|
4
|
-
import { aabb3_score_boxes_SAH } from "../../geom/3d/aabb/aabb3_score_boxes_SAH.js";
|
|
5
|
-
import { aabb3_box_surface_area_2 } from "../../geom/3d/aabb/aabb3_box_surface_area_2.js";
|
|
6
|
-
|
|
7
|
-
function BottomUpOptimizingRebuilder() {
|
|
8
|
-
this.root = null;
|
|
9
|
-
this.nodes = [];
|
|
10
|
-
/**
|
|
11
|
-
* @type {function(left:NodeDescription, right:NodeDescription):number} heuristic Cost function of pairing two nodes, lower value means better pairing
|
|
12
|
-
*/
|
|
13
|
-
this.heuristic = aabb3_score_boxes_SAH;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
* @param {BinaryNode} root
|
|
19
|
-
*/
|
|
20
|
-
BottomUpOptimizingRebuilder.prototype.init = function (root) {
|
|
21
|
-
this.root = root;
|
|
22
|
-
const nodes = this.nodes = [];
|
|
23
|
-
const binaryNodePool = this.binaryNodePool = [];
|
|
24
|
-
|
|
25
|
-
//first extract all leaf nodes
|
|
26
|
-
root.traversePreOrderUsingStack(function (node) {
|
|
27
|
-
if (isLeaf(node)) {
|
|
28
|
-
nodes.push(node);
|
|
29
|
-
} else if (node !== root) {
|
|
30
|
-
//collect intermediate nodes for reuse
|
|
31
|
-
binaryNodePool.push(node);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* Factory to allow reuse of existing node, avoiding garbage collection
|
|
37
|
-
* @returns {BinaryNode}
|
|
38
|
-
*/
|
|
39
|
-
BottomUpOptimizingRebuilder.prototype.makeBinaryNode = function () {
|
|
40
|
-
if (this.binaryNodePool.length > 0) {
|
|
41
|
-
return this.binaryNodePool.pop();
|
|
42
|
-
} else {
|
|
43
|
-
return new BinaryNode();
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
*
|
|
49
|
-
* @param {number} maxSteps
|
|
50
|
-
* @returns {boolean} true when complete
|
|
51
|
-
*/
|
|
52
|
-
BottomUpOptimizingRebuilder.prototype.compute = function (maxSteps) {
|
|
53
|
-
const self = this;
|
|
54
|
-
/**
|
|
55
|
-
*
|
|
56
|
-
* @type {Array.<NodeDescription>}
|
|
57
|
-
*/
|
|
58
|
-
const nodes = this.nodes;
|
|
59
|
-
|
|
60
|
-
let nodeCount = nodes.length;
|
|
61
|
-
|
|
62
|
-
const heuristic = this.heuristic;
|
|
63
|
-
|
|
64
|
-
let stepsRemaining = maxSteps;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
while (nodeCount > 2 && stepsRemaining-- >= 0) {
|
|
68
|
-
let bestI = -1;
|
|
69
|
-
let bestJ = -1;
|
|
70
|
-
let bestCost = Number.POSITIVE_INFINITY;
|
|
71
|
-
for (let i = 0; i < nodeCount - 1; i++) {
|
|
72
|
-
const first = nodes[i];
|
|
73
|
-
for (let j = i + 1; j < nodeCount; j++) {
|
|
74
|
-
const second = nodes[j];
|
|
75
|
-
|
|
76
|
-
const cost = heuristic(first, second);
|
|
77
|
-
|
|
78
|
-
if (cost < bestCost) {
|
|
79
|
-
bestCost = cost;
|
|
80
|
-
|
|
81
|
-
bestI = i;
|
|
82
|
-
bestJ = j;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const first = nodes[bestI];
|
|
88
|
-
const second = nodes[bestJ];
|
|
89
|
-
|
|
90
|
-
const binaryNode = self.makeBinaryNode();
|
|
91
|
-
binaryNode.setChildren(first, second);
|
|
92
|
-
|
|
93
|
-
//transplant new node in place of the second removed node
|
|
94
|
-
nodes[bestI] = binaryNode;
|
|
95
|
-
nodes.splice(bestJ, 1);
|
|
96
|
-
|
|
97
|
-
nodeCount--;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const root = this.root;
|
|
101
|
-
|
|
102
|
-
if (nodeCount === 2) {
|
|
103
|
-
root.setChildren(nodes[0], nodes[1]);
|
|
104
|
-
return true;
|
|
105
|
-
} else if (nodeCount === 1) {
|
|
106
|
-
root.left = nodes[0];
|
|
107
|
-
root.left.parentNode = root;
|
|
108
|
-
root.refit();
|
|
109
|
-
return true;
|
|
110
|
-
} else if (nodeCount === 0) {
|
|
111
|
-
//no nodes, we're done
|
|
112
|
-
return true;
|
|
113
|
-
} else {
|
|
114
|
-
//not done yet
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const leafCounts = new Map();
|
|
120
|
-
|
|
121
|
-
function leaves(node) {
|
|
122
|
-
if (leafCounts.has(node)) {
|
|
123
|
-
return leafCounts.get(node);
|
|
124
|
-
} else {
|
|
125
|
-
const count = countLeaves(node);
|
|
126
|
-
leafCounts.set(node, count);
|
|
127
|
-
return count;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function sah(left, right) {
|
|
132
|
-
const leftArea = aabb3_box_surface_area_2(left);
|
|
133
|
-
const rightArea = aabb3_box_surface_area_2(right);
|
|
134
|
-
|
|
135
|
-
const leftLeaves = leaves(left);
|
|
136
|
-
const rightLeaves = leaves(right);
|
|
137
|
-
|
|
138
|
-
const commonArea = aabb3_score_boxes_SAH(left, right);
|
|
139
|
-
|
|
140
|
-
return surfaceAreaHeuristic(commonArea, leftArea, rightArea, leftLeaves, rightLeaves);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
export { BottomUpOptimizingRebuilder };
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { BinaryNode } from "../BinaryNode.js";
|
|
2
|
-
import { isLeaf } from "../LeafNode.js";
|
|
3
|
-
import { StacklessTraverser } from "../StacklessTraverser.js";
|
|
4
|
-
import { tryRotateSingleNode } from "./tryRotateSingleNode.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
9
|
-
* @type {(BinaryNode|LeafNode)[]}
|
|
10
|
-
*/
|
|
11
|
-
const stack = [];
|
|
12
|
-
let stackPointer = 0;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* * @param {BinaryNode} node
|
|
16
|
-
* @param {Map.<NodeDescription,int>} leafCounts
|
|
17
|
-
*/
|
|
18
|
-
function getLeafCount(node, leafCounts) {
|
|
19
|
-
if (isLeaf(node)) {
|
|
20
|
-
return 1;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let result = 0;
|
|
24
|
-
|
|
25
|
-
let n;
|
|
26
|
-
|
|
27
|
-
const storedValue = leafCounts.get(node);
|
|
28
|
-
|
|
29
|
-
if (storedValue !== undefined) {
|
|
30
|
-
return storedValue;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const stackOffset = stackPointer;
|
|
34
|
-
|
|
35
|
-
stack[stackPointer++] = node;
|
|
36
|
-
|
|
37
|
-
while (stackPointer-- > stackOffset) {
|
|
38
|
-
|
|
39
|
-
n = stack[stackPointer];
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const storedValue = leafCounts.get(node);
|
|
43
|
-
|
|
44
|
-
if (storedValue !== undefined) {
|
|
45
|
-
result += storedValue;
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (n.isBinaryNode) {
|
|
51
|
-
|
|
52
|
-
if (n.right !== null) {
|
|
53
|
-
stack[stackPointer++] = n.right;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (n.left !== null) {
|
|
57
|
-
stack[stackPointer++] = n.left;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
} else {
|
|
61
|
-
|
|
62
|
-
result++;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
//drop the stack frame
|
|
68
|
-
stackPointer = stackOffset;
|
|
69
|
-
|
|
70
|
-
leafCounts.set(node, result);
|
|
71
|
-
|
|
72
|
-
return result;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
*
|
|
77
|
-
* @param {BinaryNode} root
|
|
78
|
-
* @param {int} maxIterations
|
|
79
|
-
*/
|
|
80
|
-
export function optimize(root, maxIterations = 1000) {
|
|
81
|
-
const traverser = new StacklessTraverser();
|
|
82
|
-
|
|
83
|
-
traverser.init(root);
|
|
84
|
-
|
|
85
|
-
let changeCounter = 0;
|
|
86
|
-
|
|
87
|
-
const leafCounts = new Map();
|
|
88
|
-
|
|
89
|
-
function visit(node) {
|
|
90
|
-
|
|
91
|
-
if (isLeaf(node)) {
|
|
92
|
-
//skip leaves
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const rotationType = tryRotateSingleNode(node, leafCounts);
|
|
97
|
-
if (rotationType !== 0) {
|
|
98
|
-
changeCounter++;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
let oldChangeCounter = changeCounter;
|
|
103
|
-
|
|
104
|
-
let i;
|
|
105
|
-
for (i = 0; i < maxIterations; i++) {
|
|
106
|
-
const canAdvance = traverser.advance(visit);
|
|
107
|
-
if (!canAdvance) {
|
|
108
|
-
//check if we have made any rotations in this traversal pass
|
|
109
|
-
if (oldChangeCounter === changeCounter) {
|
|
110
|
-
//done, no changes
|
|
111
|
-
break;
|
|
112
|
-
} else {
|
|
113
|
-
oldChangeCounter = changeCounter;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
//re-initialize the traverser
|
|
117
|
-
traverser.init(root);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return changeCounter;
|
|
123
|
-
}
|