@woosh/meep-engine 2.68.0 → 2.70.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-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/build/meep.cjs +1090 -1581
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +1090 -1581
- package/package.json +1 -1
- package/src/core/__module.js +1 -0
- package/src/core/binary/BinaryBuffer.js +37 -31
- package/src/core/bvh2/binary/2/BinaryUint32BVH.js +76 -52
- package/src/core/bvh2/binary/2/BinaryUint32BVH.spec.js +5 -7
- 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/cone/compute_bounding_cone_of_2_cones.js +3 -2
- 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/morton/v3_morton_encode_bounded.js +34 -0
- package/src/core/geom/3d/morton/v3_morton_encode_transformed.js +2 -1
- package/src/core/geom/3d/quaternion/quat3_createFromAxisAngle.js +11 -0
- package/src/core/geom/3d/quaternion/quat_decode_from_uint32.js +53 -0
- package/src/core/geom/3d/quaternion/quat_encode_to_uint32.js +106 -0
- package/src/core/geom/3d/triangle/triangle_intersects_clipping_volume.js +51 -0
- package/src/core/geom/Quaternion.js +8 -142
- package/src/core/geom/Vector2.js +6 -7
- package/src/core/geom/Vector3.js +15 -82
- package/src/core/geom/vec3/v3_binary_equality_decode.js +44 -0
- package/src/core/geom/vec3/v3_binary_equality_encode.js +47 -0
- package/src/core/primitives/numbers/computeHashFloat.js +2 -2
- 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/ecs/transform/Transform.js +8 -9
- package/src/engine/ecs/transform/TransformSerializationAdapter.js +18 -7
- package/src/engine/graphics/ecs/mesh/Mesh.js +11 -11
- 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/render/forward_plus/LightManager.js +2 -2
- 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/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/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/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/buffered/BinaryBVHFromBufferGeometry.js +0 -123
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Created by Alex on 24/05/2016.
|
|
3
|
-
*/
|
|
4
|
-
import PrimitiveType from "../../binary/type/PrimitiveTypes.js";
|
|
5
|
-
import BinaryStructure from "../../binary/type/Type.js";
|
|
6
|
-
import { aabb3_intersects_ray } from "../../geom/3d/aabb/aabb3_intersects_ray.js";
|
|
7
|
-
|
|
8
|
-
const NodeType = {
|
|
9
|
-
LEAF: 0,
|
|
10
|
-
BINARY: 1
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const sBox = new BinaryStructure();
|
|
14
|
-
sBox.addField('x0', PrimitiveType.Float32);
|
|
15
|
-
sBox.addField('y0', PrimitiveType.Float32);
|
|
16
|
-
sBox.addField('z0', PrimitiveType.Float32);
|
|
17
|
-
sBox.addField('x1', PrimitiveType.Float32);
|
|
18
|
-
sBox.addField('y1', PrimitiveType.Float32);
|
|
19
|
-
sBox.addField('z1', PrimitiveType.Float32);
|
|
20
|
-
|
|
21
|
-
const sNode = sBox.clone();
|
|
22
|
-
sNode.addField('type', PrimitiveType.Uint8);
|
|
23
|
-
|
|
24
|
-
const sNodeLeaf = sNode.clone();
|
|
25
|
-
sNodeLeaf.addField('index', PrimitiveType.Uint32);
|
|
26
|
-
|
|
27
|
-
const sNodeBinary = sNode.clone();
|
|
28
|
-
sNodeBinary.addField('left', PrimitiveType.Uint32);
|
|
29
|
-
sNodeBinary.addField('right', PrimitiveType.Uint32);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const daNode = sNode.generateDataAccess();
|
|
33
|
-
|
|
34
|
-
const daNodeLeaf = sNodeLeaf.generateDataAccess();
|
|
35
|
-
const daNodeBinary = sNodeBinary.generateDataAccess();
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
*
|
|
39
|
-
* @param leafCount
|
|
40
|
-
* @constructor
|
|
41
|
-
*/
|
|
42
|
-
const BinaryBVH = function (leafCount) {
|
|
43
|
-
const twoLog = Math.log(leafCount) / Math.log(2);
|
|
44
|
-
|
|
45
|
-
const twoLeafLimit = Math.pow(2, Math.ceil(twoLog));
|
|
46
|
-
const binaryNodeCount = twoLeafLimit - 1;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this.nodeByteSize = sNode.byteSize;
|
|
50
|
-
|
|
51
|
-
this.leafNodeCount = leafCount;
|
|
52
|
-
this.leafNodeByteSize = this.nodeByteSize + 4;
|
|
53
|
-
|
|
54
|
-
this.binaryNodeByteSize = this.nodeByteSize + 4 * 2;
|
|
55
|
-
|
|
56
|
-
this.binaryNodeCount = binaryNodeCount;
|
|
57
|
-
|
|
58
|
-
this.leafNodesOffset = this.binaryNodeByteSize * binaryNodeCount;
|
|
59
|
-
|
|
60
|
-
this.totalByteSize = this.binaryNodeByteSize * this.binaryNodeCount + this.leafNodeByteSize * this.leafNodeCount;
|
|
61
|
-
|
|
62
|
-
this.byteBuffer = new ArrayBuffer(this.totalByteSize);
|
|
63
|
-
this.dataView = new DataView(this.byteBuffer);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
function copyBox(from, to, dataView) {
|
|
68
|
-
const x0 = daNode.read_x0(dataView, from);
|
|
69
|
-
const y0 = daNode.read_y0(dataView, from);
|
|
70
|
-
const z0 = daNode.read_z0(dataView, from);
|
|
71
|
-
|
|
72
|
-
const x1 = daNode.read_x1(dataView, from);
|
|
73
|
-
const y1 = daNode.read_y1(dataView, from);
|
|
74
|
-
const z1 = daNode.read_z1(dataView, from);
|
|
75
|
-
|
|
76
|
-
daNode.write_x0(dataView, to, x0);
|
|
77
|
-
daNode.write_y0(dataView, to, y0);
|
|
78
|
-
daNode.write_z0(dataView, to, z0);
|
|
79
|
-
|
|
80
|
-
daNode.write_x1(dataView, to, x1);
|
|
81
|
-
daNode.write_y1(dataView, to, y1);
|
|
82
|
-
daNode.write_z1(dataView, to, z1);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function binaryNodeSetChildren(dataView, binaryNode, childNode0, childNode1) {
|
|
86
|
-
daNodeBinary.write_type(dataView, binaryNode, NodeType.BINARY);
|
|
87
|
-
daNodeBinary.write_left(dataView, binaryNode, childNode0);
|
|
88
|
-
daNodeBinary.write_right(dataView, binaryNode, childNode1);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function binaryNodeRefit(dataView, binaryNode, childNode0, childNode1) {
|
|
92
|
-
|
|
93
|
-
const ax0 = daNode.read_x0(dataView, childNode0);
|
|
94
|
-
const ay0 = daNode.read_y0(dataView, childNode0);
|
|
95
|
-
const az0 = daNode.read_z0(dataView, childNode0);
|
|
96
|
-
const ax1 = daNode.read_x1(dataView, childNode0);
|
|
97
|
-
const ay1 = daNode.read_y1(dataView, childNode0);
|
|
98
|
-
const az1 = daNode.read_z1(dataView, childNode0);
|
|
99
|
-
|
|
100
|
-
const bx0 = daNode.read_x0(dataView, childNode1);
|
|
101
|
-
const by0 = daNode.read_y0(dataView, childNode1);
|
|
102
|
-
const bz0 = daNode.read_z0(dataView, childNode1);
|
|
103
|
-
const bx1 = daNode.read_x1(dataView, childNode1);
|
|
104
|
-
const by1 = daNode.read_y1(dataView, childNode1);
|
|
105
|
-
const bz1 = daNode.read_z1(dataView, childNode1);
|
|
106
|
-
|
|
107
|
-
const x0 = Math.min(ax0, bx0);
|
|
108
|
-
const y0 = Math.min(ay0, by0);
|
|
109
|
-
const z0 = Math.min(az0, bz0);
|
|
110
|
-
|
|
111
|
-
const x1 = Math.max(ax1, bx1);
|
|
112
|
-
const y1 = Math.max(ay1, by1);
|
|
113
|
-
const z1 = Math.max(az1, bz1);
|
|
114
|
-
|
|
115
|
-
daNode.write_x0(dataView, binaryNode, x0);
|
|
116
|
-
daNode.write_y0(dataView, binaryNode, y0);
|
|
117
|
-
daNode.write_z0(dataView, binaryNode, z0);
|
|
118
|
-
daNode.write_x1(dataView, binaryNode, x1);
|
|
119
|
-
daNode.write_y1(dataView, binaryNode, y1);
|
|
120
|
-
daNode.write_z1(dataView, binaryNode, z1);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
BinaryBVH.prototype.unsortedBuiltIntermediate = function () {
|
|
125
|
-
const dataView = this.dataView;
|
|
126
|
-
|
|
127
|
-
const nodeCount = this.binaryNodeCount;
|
|
128
|
-
|
|
129
|
-
let level = Math.floor(Math.log(nodeCount) / Math.log(2));
|
|
130
|
-
|
|
131
|
-
const leafNodeByteSize = this.leafNodeByteSize;
|
|
132
|
-
const binaryNodeByteSize = this.binaryNodeByteSize;
|
|
133
|
-
|
|
134
|
-
let i, offset, levelNodeCount;
|
|
135
|
-
//NOTE: building first level separately allows to avoid some switching logic needed to determine what is the type of lower level node
|
|
136
|
-
//build one level above leaf nodes
|
|
137
|
-
levelNodeCount = Math.pow(2, level);
|
|
138
|
-
offset = ((levelNodeCount >> 1) - 1) * binaryNodeByteSize;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
for (i = 0; i < levelNodeCount; i++) {
|
|
142
|
-
const leafIndex0 = i * 2;
|
|
143
|
-
let leafIndex1 = leafIndex0 + 1;
|
|
144
|
-
|
|
145
|
-
let leafOffset0 = this.leafNodesOffset + leafIndex0 * leafNodeByteSize;
|
|
146
|
-
const leafOffset1 = this.leafNodesOffset + leafIndex1 * leafNodeByteSize;
|
|
147
|
-
|
|
148
|
-
if (leafIndex1 >= this.totalByteSize) {
|
|
149
|
-
leafIndex1 = -1;
|
|
150
|
-
if (leafOffset0 >= this.totalByteSize) {
|
|
151
|
-
leafOffset0 = -1;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
binaryNodeSetChildren(dataView, offset, leafOffset0, leafIndex1);
|
|
156
|
-
|
|
157
|
-
if (leafIndex1 < this.leafNodeCount) {
|
|
158
|
-
binaryNodeRefit(dataView, offset, leafOffset0, leafOffset1);
|
|
159
|
-
} else if (leafIndex0 < this.leafNodeCount) {
|
|
160
|
-
copyBox(leafOffset0, offset, dataView);
|
|
161
|
-
} else {
|
|
162
|
-
//don't care about the rest of the nodes
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
offset += binaryNodeByteSize;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
level--;
|
|
169
|
-
|
|
170
|
-
//build intermediate nodes
|
|
171
|
-
for (; level > 0; level--) {
|
|
172
|
-
levelNodeCount = Math.pow(2, level);
|
|
173
|
-
offset = ((levelNodeCount >> 1) - 1) * binaryNodeByteSize;
|
|
174
|
-
|
|
175
|
-
const childrenOffset = levelNodeCount * binaryNodeByteSize;
|
|
176
|
-
|
|
177
|
-
for (i = 0; i < levelNodeCount; i++) {
|
|
178
|
-
const childNode0 = childrenOffset + i * 2 * binaryNodeByteSize;
|
|
179
|
-
const childNode1 = childNode0 + binaryNodeByteSize;
|
|
180
|
-
|
|
181
|
-
binaryNodeSetChildren(dataView, offset, childNode0, childNode1);
|
|
182
|
-
binaryNodeRefit(dataView, offset, childNode0, childNode1);
|
|
183
|
-
|
|
184
|
-
offset += binaryNodeByteSize;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
//build root
|
|
189
|
-
binaryNodeSetChildren(dataView, 0, binaryNodeByteSize, binaryNodeByteSize * 2);
|
|
190
|
-
binaryNodeRefit(dataView, 0, binaryNodeByteSize, binaryNodeByteSize * 2);
|
|
191
|
-
|
|
192
|
-
//set bounds of the bvh
|
|
193
|
-
this.x0 = daNode.read_x0(dataView, 0);
|
|
194
|
-
this.y0 = daNode.read_y0(dataView, 0);
|
|
195
|
-
this.z0 = daNode.read_z0(dataView, 0);
|
|
196
|
-
this.x1 = daNode.read_x1(dataView, 0);
|
|
197
|
-
this.y1 = daNode.read_y1(dataView, 0);
|
|
198
|
-
this.z1 = daNode.read_z1(dataView, 0);
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
BinaryBVH.prototype.setLeaves = function (visitor) {
|
|
202
|
-
|
|
203
|
-
const leafNodesOffset = this.leafNodesOffset;
|
|
204
|
-
|
|
205
|
-
const leafNodeByteSize = sNodeLeaf.byteSize;
|
|
206
|
-
|
|
207
|
-
let byteOffset = leafNodesOffset;
|
|
208
|
-
|
|
209
|
-
const dataView = this.dataView;
|
|
210
|
-
|
|
211
|
-
let i = 0;
|
|
212
|
-
const l = this.leafNodeCount;
|
|
213
|
-
for (; i < l; i++) {
|
|
214
|
-
const valueToStore = visitor(i, byteOffset, dataView, daNodeLeaf);
|
|
215
|
-
|
|
216
|
-
daNodeLeaf.write_type(dataView, byteOffset, NodeType.LEAF);
|
|
217
|
-
daNodeLeaf.write_index(dataView, byteOffset, valueToStore);
|
|
218
|
-
|
|
219
|
-
byteOffset += leafNodeByteSize;
|
|
220
|
-
}
|
|
221
|
-
this.unsortedBuiltIntermediate();
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
BinaryBVH.prototype.traversePreOrder = function (visitor, address, type) {
|
|
225
|
-
const dataView = this.dataView;
|
|
226
|
-
const carryOn = visitor(address, type);
|
|
227
|
-
if (carryOn !== false) {
|
|
228
|
-
|
|
229
|
-
const leftAddress = daNodeLeaf.read_left(dataView, address);
|
|
230
|
-
const rightAddress = daNodeLeaf.read_right(dataView, address);
|
|
231
|
-
//left
|
|
232
|
-
if (leftAddress >= 0) {
|
|
233
|
-
const leftType = daNode.read_type(dataView, leftAddress);
|
|
234
|
-
if (leftType === NodeType.BINARY) {
|
|
235
|
-
this.traversePreOrder(visitor, leftAddress, leftType);
|
|
236
|
-
} else if (leftType === NodeType.LEAF) {
|
|
237
|
-
visitor(leftAddress, leftType);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
//right
|
|
241
|
-
if (rightAddress >= 0) {
|
|
242
|
-
const rightType = daNode.read_type(dataView, rightAddress);
|
|
243
|
-
if (rightType === NodeType.BINARY) {
|
|
244
|
-
this.traversePreOrder(visitor, rightAddress, rightType);
|
|
245
|
-
} else if (rightType === NodeType.LEAF) {
|
|
246
|
-
visitor(rightAddress, rightType);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
BinaryBVH.prototype.traverseRayLeafIntersections = function (startX, startY, startZ, directionX, directionY, directionZ, visitor) {
|
|
253
|
-
|
|
254
|
-
const dataView = this.dataView;
|
|
255
|
-
|
|
256
|
-
this.traversePreOrder(function (address, type) {
|
|
257
|
-
const x0 = daNode.read_x0(dataView, address);
|
|
258
|
-
const y0 = daNode.read_y0(dataView, address);
|
|
259
|
-
const z0 = daNode.read_z0(dataView, address);
|
|
260
|
-
|
|
261
|
-
const x1 = daNode.read_x1(dataView, address);
|
|
262
|
-
const y1 = daNode.read_y1(dataView, address);
|
|
263
|
-
const z1 = daNode.read_z1(dataView, address);
|
|
264
|
-
|
|
265
|
-
let b = aabb3_intersects_ray(x0, y0, z0, x1, y1, z1, startX, startY, startZ, directionX, directionY, directionZ);
|
|
266
|
-
|
|
267
|
-
if (!b) {
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (type === NodeType.LEAF) {
|
|
272
|
-
const value = daNodeLeaf.read_index(dataView, address);
|
|
273
|
-
visitor(value, address, type);
|
|
274
|
-
return false;
|
|
275
|
-
} else {
|
|
276
|
-
return true;
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
export default BinaryBVH;
|
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Created by Alex on 29/05/2016.
|
|
3
|
-
*/
|
|
4
|
-
import { max2 } from "../../math/max2.js";
|
|
5
|
-
import { min2 } from "../../math/min2.js";
|
|
6
|
-
import { IndexedBinaryBVHVisitor } from "./IndexedBinaryBVHVisitor.js";
|
|
7
|
-
import { NodeType } from "./NodeType.js";
|
|
8
|
-
import { RayLeafIntersectionVisitor } from "./RayLeafIntersectionVisitor.js";
|
|
9
|
-
import { array_copy } from "../../collection/array/array_copy.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
*
|
|
14
|
-
* @type {Float32Array|number[]}
|
|
15
|
-
*/
|
|
16
|
-
const scratch_aabb_0 = new Float32Array(6);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export default class IndexedBinaryBVH {
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
* @constructor
|
|
23
|
-
*/
|
|
24
|
-
constructor() {
|
|
25
|
-
/**
|
|
26
|
-
*
|
|
27
|
-
* @type {number}
|
|
28
|
-
*/
|
|
29
|
-
this.leafNodeCount = 0;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
*
|
|
33
|
-
* @type {number}
|
|
34
|
-
*/
|
|
35
|
-
this.binaryNodeCount = 0;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Total number of boxes contained in the tree, some might be unused
|
|
39
|
-
* @type {number}
|
|
40
|
-
*/
|
|
41
|
-
this.boxCount = 0;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
45
|
-
* @type {Float32Array|number[]}
|
|
46
|
-
*/
|
|
47
|
-
this.data = new Float32Array(16);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
*
|
|
52
|
-
* @returns {number}
|
|
53
|
-
*/
|
|
54
|
-
estimateByteSize(){
|
|
55
|
-
return this.data.buffer.byteLength + 248;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
*
|
|
60
|
-
* @param {int} leafCount
|
|
61
|
-
*/
|
|
62
|
-
initialize(leafCount) {
|
|
63
|
-
|
|
64
|
-
const twoLog = Math.log(leafCount) / Math.log(2);
|
|
65
|
-
|
|
66
|
-
const twoLeafLimit = Math.pow(2, Math.ceil(twoLog));
|
|
67
|
-
const binaryNodeCount = twoLeafLimit - 1;
|
|
68
|
-
|
|
69
|
-
this.leafNodeCount = leafCount;
|
|
70
|
-
|
|
71
|
-
this.binaryNodeCount = binaryNodeCount;
|
|
72
|
-
|
|
73
|
-
this.boxCount = this.leafNodeCount + this.binaryNodeCount;
|
|
74
|
-
|
|
75
|
-
// possibly resize the storage
|
|
76
|
-
const storage_size = this.boxCount * 6;
|
|
77
|
-
|
|
78
|
-
if (this.data.length < storage_size) {
|
|
79
|
-
this.data = new Float32Array(storage_size);
|
|
80
|
-
} else {
|
|
81
|
-
this.data.fill(0);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
unsortedBuiltIntermediate() {
|
|
86
|
-
const data = this.data;
|
|
87
|
-
|
|
88
|
-
const nodeCount = this.binaryNodeCount;
|
|
89
|
-
|
|
90
|
-
const leafNodesOffset = this.binaryNodeCount * 6;
|
|
91
|
-
|
|
92
|
-
let level = Math.floor(Math.log(nodeCount) / Math.log(2));
|
|
93
|
-
|
|
94
|
-
let i, offset, levelNodeCount;
|
|
95
|
-
//NOTE: building first level separately allows to avoid some switching logic needed to determine what is the type of lower level node
|
|
96
|
-
//build one level above leaf nodes
|
|
97
|
-
levelNodeCount = Math.pow(2, level);
|
|
98
|
-
offset = (levelNodeCount - 1) * 6;
|
|
99
|
-
|
|
100
|
-
let parentIndex, childIndex0, childIndex1;
|
|
101
|
-
|
|
102
|
-
for (i = 0; i < levelNodeCount; i++) {
|
|
103
|
-
const leafIndex0 = i * 2;
|
|
104
|
-
const leafIndex1 = leafIndex0 + 1;
|
|
105
|
-
|
|
106
|
-
const leafOffset0 = leafNodesOffset + leafIndex0 * 6;
|
|
107
|
-
const leafOffset1 = leafNodesOffset + leafIndex1 * 6;
|
|
108
|
-
|
|
109
|
-
if (leafIndex1 < this.leafNodeCount) {
|
|
110
|
-
binaryNodeRefit(data, offset, leafOffset0, leafOffset1);
|
|
111
|
-
} else if (leafIndex0 < this.leafNodeCount) {
|
|
112
|
-
copyBox(leafOffset0, offset, data);
|
|
113
|
-
} else {
|
|
114
|
-
//initialize to 0-size box same position as previous node
|
|
115
|
-
copyBoxZeroSize(offset - 6, offset, data);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
offset += 6;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
level--;
|
|
122
|
-
|
|
123
|
-
//build intermediate nodes
|
|
124
|
-
for (; level >= 0; level--) {
|
|
125
|
-
levelNodeCount = Math.pow(2, level);
|
|
126
|
-
parentIndex = (levelNodeCount - 1);
|
|
127
|
-
|
|
128
|
-
for (i = 0; i < levelNodeCount; i++) {
|
|
129
|
-
|
|
130
|
-
childIndex0 = (parentIndex << 1) + 1;
|
|
131
|
-
childIndex1 = childIndex0 + 1;
|
|
132
|
-
|
|
133
|
-
binaryNodeRefit(data, parentIndex * 6, childIndex0 * 6, childIndex1 * 6);
|
|
134
|
-
|
|
135
|
-
parentIndex++;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
//set bounds of the bvh
|
|
140
|
-
array_copy(data, 0, scratch_aabb_0, 0, 6);
|
|
141
|
-
|
|
142
|
-
this.x0 = scratch_aabb_0[0];
|
|
143
|
-
this.y0 = scratch_aabb_0[1];
|
|
144
|
-
this.z0 = scratch_aabb_0[2];
|
|
145
|
-
this.x1 = scratch_aabb_0[3];
|
|
146
|
-
this.y1 = scratch_aabb_0[4];
|
|
147
|
-
this.z1 = scratch_aabb_0[5];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Sets bounds of a given leaf
|
|
152
|
-
* NOTE: to build tree, must call {@link #unsortedBuiltIntermediate} after all leaves are set
|
|
153
|
-
* @param {number} leaf_index
|
|
154
|
-
* @param {number} x0
|
|
155
|
-
* @param {number} y0
|
|
156
|
-
* @param {number} z0
|
|
157
|
-
* @param {number} x1
|
|
158
|
-
* @param {number} y1
|
|
159
|
-
* @param {number} z1
|
|
160
|
-
*/
|
|
161
|
-
writeLeaf(leaf_index, x0, y0, z0, x1, y1, z1) {
|
|
162
|
-
const offset = this.binaryNodeCount * 6 + leaf_index * 6;
|
|
163
|
-
writeBox(this.data, offset, x0, y0, z0, x1, y1, z1);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* @template T
|
|
168
|
-
* @deprecated use {@link #writeLeaf} instead followed by {@link #unsortedBuiltIntermediate}
|
|
169
|
-
* @param {function(index:number,offset:number,data:T, writeBox:function):void} visitor
|
|
170
|
-
*/
|
|
171
|
-
setLeafs(visitor) {
|
|
172
|
-
let offset = this.binaryNodeCount * 6;
|
|
173
|
-
|
|
174
|
-
const data = this.data;
|
|
175
|
-
|
|
176
|
-
let i = 0;
|
|
177
|
-
const l = this.leafNodeCount;
|
|
178
|
-
for (; i < l; i++) {
|
|
179
|
-
visitor(i, offset, data, writeBox);
|
|
180
|
-
|
|
181
|
-
offset += 6;
|
|
182
|
-
}
|
|
183
|
-
this.unsortedBuiltIntermediate();
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
*
|
|
188
|
-
* @param {IndexedBinaryBVHVisitor} visitor
|
|
189
|
-
* @param {Number} startIndex
|
|
190
|
-
*/
|
|
191
|
-
traversePreOrderStack(visitor, startIndex) {
|
|
192
|
-
|
|
193
|
-
const stackOffset = stackPointer;
|
|
194
|
-
|
|
195
|
-
stack[stackPointer++] = startIndex;
|
|
196
|
-
|
|
197
|
-
const nodeThreshold = this.binaryNodeCount * 6;
|
|
198
|
-
const endAddress = this.boxCount * 6;
|
|
199
|
-
|
|
200
|
-
while (stackPointer-- > stackOffset) {
|
|
201
|
-
|
|
202
|
-
const index = stack[stackPointer];
|
|
203
|
-
|
|
204
|
-
const address = index * 6;
|
|
205
|
-
|
|
206
|
-
const split = visitor.visit(address, NodeType.BINARY);
|
|
207
|
-
if (split) {
|
|
208
|
-
|
|
209
|
-
const leftIndex = (index << 1) + 1;
|
|
210
|
-
const rightIndex = leftIndex + 1;
|
|
211
|
-
|
|
212
|
-
const leftAddress = leftIndex * 6;
|
|
213
|
-
const rightAddress = rightIndex * 6;
|
|
214
|
-
|
|
215
|
-
//right
|
|
216
|
-
if (rightAddress < endAddress) {
|
|
217
|
-
if (rightAddress < nodeThreshold) {
|
|
218
|
-
stack[stackPointer++] = rightIndex;
|
|
219
|
-
} else {
|
|
220
|
-
visitor.visit(rightAddress, NodeType.LEAF);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
//left
|
|
225
|
-
if (leftAddress < endAddress) {
|
|
226
|
-
if (leftAddress < nodeThreshold) {
|
|
227
|
-
stack[stackPointer++] = leftIndex;
|
|
228
|
-
} else {
|
|
229
|
-
visitor.visit(leftAddress, NodeType.LEAF);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
//drop stack
|
|
236
|
-
stackPointer = stackOffset;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
*
|
|
241
|
-
* @param {function} visitor
|
|
242
|
-
* @param {number} index
|
|
243
|
-
* @param {number} type
|
|
244
|
-
*/
|
|
245
|
-
traversePreOrder(visitor, index, type) {
|
|
246
|
-
const address = index * 6;
|
|
247
|
-
const carryOn = visitor(address, type);
|
|
248
|
-
const nodeThreshold = this.binaryNodeCount * 6;
|
|
249
|
-
const endAddress = this.boxCount * 6;
|
|
250
|
-
|
|
251
|
-
if (carryOn !== false) {
|
|
252
|
-
|
|
253
|
-
const leftIndex = (index << 1) + 1;
|
|
254
|
-
const rightIndex = leftIndex + 1;
|
|
255
|
-
|
|
256
|
-
const leftAddress = leftIndex * 6;
|
|
257
|
-
const rightAddress = rightIndex * 6;
|
|
258
|
-
//left
|
|
259
|
-
if (leftAddress < endAddress) {
|
|
260
|
-
if (leftAddress < nodeThreshold) {
|
|
261
|
-
this.traversePreOrder(visitor, leftIndex, NodeType.BINARY);
|
|
262
|
-
} else {
|
|
263
|
-
visitor(leftAddress, NodeType.LEAF);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
//right
|
|
267
|
-
if (rightAddress < endAddress) {
|
|
268
|
-
if (rightAddress < nodeThreshold) {
|
|
269
|
-
this.traversePreOrder(visitor, rightIndex, NodeType.BINARY);
|
|
270
|
-
} else {
|
|
271
|
-
visitor(rightAddress, NodeType.LEAF);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* @deprecated use a visitor object instead
|
|
279
|
-
* @param {number} startX
|
|
280
|
-
* @param {number} startY
|
|
281
|
-
* @param {number} startZ
|
|
282
|
-
* @param {number} directionX
|
|
283
|
-
* @param {number} directionY
|
|
284
|
-
* @param {number} directionZ
|
|
285
|
-
* @param {function} visitor
|
|
286
|
-
* @param {*} [thisArg]
|
|
287
|
-
*/
|
|
288
|
-
traverseRayLeafIntersections(startX, startY, startZ, directionX, directionY, directionZ, visitor, thisArg) {
|
|
289
|
-
rayLeafIntersectionVisitor.originX = startX;
|
|
290
|
-
rayLeafIntersectionVisitor.originY = startY;
|
|
291
|
-
rayLeafIntersectionVisitor.originZ = startZ;
|
|
292
|
-
|
|
293
|
-
rayLeafIntersectionVisitor.directionX = directionX;
|
|
294
|
-
rayLeafIntersectionVisitor.directionY = directionY;
|
|
295
|
-
rayLeafIntersectionVisitor.directionZ = directionZ;
|
|
296
|
-
|
|
297
|
-
rayLeafIntersectionVisitor.root = this;
|
|
298
|
-
rayLeafIntersectionVisitor.callback = visitor;
|
|
299
|
-
rayLeafIntersectionVisitor.callbackThisArg = thisArg;
|
|
300
|
-
|
|
301
|
-
this.traversePreOrderStack(rayLeafIntersectionVisitor, 0);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
*
|
|
307
|
-
* @param {number[]|Float32Array} source
|
|
308
|
-
* @param {number} source_address_0
|
|
309
|
-
* @param {number} source_address_1
|
|
310
|
-
* @param {number[]|Float32Array} destination
|
|
311
|
-
* @param {number} destination_offset
|
|
312
|
-
*/
|
|
313
|
-
function contain_box_array(source, source_address_0, source_address_1, destination, destination_offset) {
|
|
314
|
-
|
|
315
|
-
const ax0 = source[source_address_0];
|
|
316
|
-
const ay0 = source[source_address_0 + 1];
|
|
317
|
-
const az0 = source[source_address_0 + 2];
|
|
318
|
-
const ax1 = source[source_address_0 + 3];
|
|
319
|
-
const ay1 = source[source_address_0 + 4];
|
|
320
|
-
const az1 = source[source_address_0 + 5];
|
|
321
|
-
|
|
322
|
-
const bx0 = source[source_address_1];
|
|
323
|
-
const by0 = source[source_address_1 + 1];
|
|
324
|
-
const bz0 = source[source_address_1 + 2];
|
|
325
|
-
const bx1 = source[source_address_1 + 3];
|
|
326
|
-
const by1 = source[source_address_1 + 4];
|
|
327
|
-
const bz1 = source[source_address_1 + 5];
|
|
328
|
-
|
|
329
|
-
const x0 = min2(ax0, bx0);
|
|
330
|
-
const y0 = min2(ay0, by0);
|
|
331
|
-
const z0 = min2(az0, bz0);
|
|
332
|
-
|
|
333
|
-
const x1 = max2(ax1, bx1);
|
|
334
|
-
const y1 = max2(ay1, by1);
|
|
335
|
-
const z1 = max2(az1, bz1);
|
|
336
|
-
|
|
337
|
-
destination[destination_offset] = x0;
|
|
338
|
-
destination[destination_offset + 1] = y0;
|
|
339
|
-
destination[destination_offset + 2] = z0;
|
|
340
|
-
destination[destination_offset + 3] = x1;
|
|
341
|
-
destination[destination_offset + 4] = y1;
|
|
342
|
-
destination[destination_offset + 5] = z1;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
*
|
|
347
|
-
* @param {Float32Array} array
|
|
348
|
-
* @param {number} address
|
|
349
|
-
* @param {number} x0
|
|
350
|
-
* @param {number} y0
|
|
351
|
-
* @param {number} z0
|
|
352
|
-
* @param {number} x1
|
|
353
|
-
* @param {number} y1
|
|
354
|
-
* @param {number} z1
|
|
355
|
-
*/
|
|
356
|
-
function writeBox(array, address, x0, y0, z0, x1, y1, z1) {
|
|
357
|
-
array[address] = x0;
|
|
358
|
-
array[address + 1] = y0;
|
|
359
|
-
array[address + 2] = z0;
|
|
360
|
-
array[address + 3] = x1;
|
|
361
|
-
array[address + 4] = y1;
|
|
362
|
-
array[address + 5] = z1;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
*
|
|
367
|
-
* @param {number} from
|
|
368
|
-
* @param {number} to
|
|
369
|
-
* @param {Float32Array} array
|
|
370
|
-
*/
|
|
371
|
-
function copyBox(from, to, array) {
|
|
372
|
-
array_copy(array, from, array, to, 6);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
*
|
|
377
|
-
* @param {number} from
|
|
378
|
-
* @param {number} to
|
|
379
|
-
* @param {Float32Array|number[]} array
|
|
380
|
-
*/
|
|
381
|
-
function copyBoxZeroSize(from, to, array) {
|
|
382
|
-
array_copy(array, from, scratch_aabb_0, 0, 3);
|
|
383
|
-
|
|
384
|
-
scratch_aabb_0[3] = scratch_aabb_0[0];
|
|
385
|
-
scratch_aabb_0[4] = scratch_aabb_0[1];
|
|
386
|
-
scratch_aabb_0[5] = scratch_aabb_0[2];
|
|
387
|
-
|
|
388
|
-
array_copy(scratch_aabb_0, 0, array, to, 6);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
*
|
|
393
|
-
* @param {Float32Array} array
|
|
394
|
-
* @param {number} binaryNode
|
|
395
|
-
* @param {number} childNode0
|
|
396
|
-
* @param {number} childNode1
|
|
397
|
-
*/
|
|
398
|
-
function binaryNodeRefit(array, binaryNode, childNode0, childNode1) {
|
|
399
|
-
contain_box_array(array, childNode0, childNode1, array, binaryNode);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const stack = [];
|
|
404
|
-
let stackPointer = 0;
|
|
405
|
-
|
|
406
|
-
const rayLeafIntersectionVisitor = new RayLeafIntersectionVisitor();
|
|
407
|
-
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import IndexedBinaryBVH from "./IndexedBinaryBVH.js";
|
|
2
|
-
|
|
3
|
-
test("constructor does not throw", () => {
|
|
4
|
-
expect(() => new IndexedBinaryBVH()).not.toThrow();
|
|
5
|
-
});
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
test("build a tree with a single leaf", () => {
|
|
9
|
-
const bvh = new IndexedBinaryBVH();
|
|
10
|
-
|
|
11
|
-
bvh.initialize(1);
|
|
12
|
-
bvh.writeLeaf(0, -1, -3, -7, 11, 13, 17);
|
|
13
|
-
|
|
14
|
-
bvh.unsortedBuiltIntermediate();
|
|
15
|
-
|
|
16
|
-
expect(bvh.leafNodeCount).toBe(1);
|
|
17
|
-
expect(bvh.binaryNodeCount).toBe(0);
|
|
18
|
-
|
|
19
|
-
expect(bvh.x0).toBe(-1);
|
|
20
|
-
expect(bvh.y0).toBe(-3);
|
|
21
|
-
expect(bvh.z0).toBe(-7);
|
|
22
|
-
|
|
23
|
-
expect(bvh.x1).toBe(11);
|
|
24
|
-
expect(bvh.y1).toBe(13);
|
|
25
|
-
expect(bvh.z1).toBe(17);
|
|
26
|
-
|
|
27
|
-
});
|