@woosh/meep-engine 2.119.127 → 2.119.128
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/package.json +1 -1
- package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/BVH.js +23 -0
- package/src/core/bvh2/bvh3/ebvh_build_hierarchy.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/ebvh_build_hierarchy.js +2 -2
- package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts +10 -0
- package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts.map +1 -0
- package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +346 -0
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BVH.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/BVH.js"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BVH.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/BVH.js"],"names":[],"mappings":"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"}
|
|
@@ -1066,6 +1066,29 @@ export class BVH {
|
|
|
1066
1066
|
return iA;
|
|
1067
1067
|
}
|
|
1068
1068
|
|
|
1069
|
+
/**
|
|
1070
|
+
*
|
|
1071
|
+
* @param {number} parent
|
|
1072
|
+
* @param {number} child_1
|
|
1073
|
+
* @param {number} child_2
|
|
1074
|
+
*/
|
|
1075
|
+
node_assign_children(parent, child_1, child_2) {
|
|
1076
|
+
this.node_set_child1(parent, child_1);
|
|
1077
|
+
this.node_set_child2(parent, child_2);
|
|
1078
|
+
|
|
1079
|
+
this.node_set_parent(child_1, parent);
|
|
1080
|
+
this.node_set_parent(child_2, parent);
|
|
1081
|
+
|
|
1082
|
+
this.node_set_height(parent,
|
|
1083
|
+
Math.max(
|
|
1084
|
+
this.node_get_height(child_1),
|
|
1085
|
+
this.node_get_height(child_2),
|
|
1086
|
+
) + 1
|
|
1087
|
+
);
|
|
1088
|
+
|
|
1089
|
+
this.node_set_combined_aabb(parent, child_1, child_2);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1069
1092
|
/**
|
|
1070
1093
|
* Release all nodes, this essentially resets the tree to empty state
|
|
1071
1094
|
* NOTE: For performance reasons, released memory is not reset, this means that attempting to access cleared nodes' memory will yield garbage data
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ebvh_build_hierarchy.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_build_hierarchy.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ebvh_build_hierarchy.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_build_hierarchy.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,0CATW,GAAG,qBACH,MAAM,EAAE,GAAC,WAAW,oBACpB,MAAM,aACN,MAAM,EAAE,GAAC,WAAW,oBACpB,MAAM,2BACN,MAAM,0BACN,MAAM,GACJ,MAAM,CAmFlB"}
|
|
@@ -3,7 +3,6 @@ import { max2 } from "../../math/max2.js";
|
|
|
3
3
|
import { NULL_NODE } from "./BVH.js";
|
|
4
4
|
import { ebvh_nodes_sort_sah_local4 } from "./ebvh_nodes_sort_sah_local4.js";
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
/**
|
|
8
7
|
* Given a set of leaves, build intermediate node hierarchy on top, all the way up to the root
|
|
9
8
|
* Assumes nodes are spatially sorted, if not - no guarantees can be made about quality
|
|
@@ -43,7 +42,8 @@ export function ebvh_build_hierarchy(
|
|
|
43
42
|
|
|
44
43
|
for (let i = 0; i < sah_optimization_cycle_count; i++) {
|
|
45
44
|
|
|
46
|
-
//
|
|
45
|
+
// Sort intermediate nodes using small locality and SAH metric
|
|
46
|
+
// Sorting progressively larger distance pairs yields best results, based on empirical tests (AG - 2024/12/28)
|
|
47
47
|
const swap_distance = (i + 1) * 2;
|
|
48
48
|
|
|
49
49
|
ebvh_nodes_sort_sah_local4(
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Perform linear optimization across the tree, similar to rotations, but we support somewhat arbitrary depth and all possible permutations
|
|
3
|
+
* Note that the root does not move, but everything below the root is subject to change
|
|
4
|
+
* @see "Fast Parallel Construction of High-Quality Bounding Volume Hierarchies" by Kerras, NVIDIA 2013
|
|
5
|
+
* @param {BVH} bvh
|
|
6
|
+
* @param {number} root
|
|
7
|
+
* @param {number} [treelet_size]
|
|
8
|
+
*/
|
|
9
|
+
export function ebvh_optimize_treelet(bvh: BVH, root: number, treelet_size?: number): void;
|
|
10
|
+
//# sourceMappingURL=ebvh_optimize_treelet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ebvh_optimize_treelet.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_optimize_treelet.js"],"names":[],"mappings":"AAyMA;;;;;;;GAOG;AACH,2CAJW,GAAG,QACH,MAAM,iBACN,MAAM,QA0IhB"}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { assert } from "../../assert.js";
|
|
2
|
+
import { lsb_32 } from "../../binary/lsb_32.js";
|
|
3
|
+
import { bitCount } from "../../binary/operations/bitCount.js";
|
|
4
|
+
import { NULL_NODE } from "./BVH.js";
|
|
5
|
+
|
|
6
|
+
const scratch_areas = new Float32Array(256);
|
|
7
|
+
const scratch_cost = new Float32Array(256);
|
|
8
|
+
const scratch_pairings = new Uint32Array(256);
|
|
9
|
+
const scratch_treelet = new Uint32Array(16);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* @param {BVH} bvh
|
|
14
|
+
* @param {number[]} leaves
|
|
15
|
+
* @param {number} mask
|
|
16
|
+
*/
|
|
17
|
+
function assemble_mask(bvh, leaves, mask) {
|
|
18
|
+
|
|
19
|
+
const leaf_count = bitCount(mask);
|
|
20
|
+
|
|
21
|
+
if (leaf_count === 1) {
|
|
22
|
+
const leaf_index = lsb_32(mask);
|
|
23
|
+
return leaves[leaf_index];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let partitioning_left = scratch_pairings[mask];
|
|
27
|
+
let partition_right = mask & ~(partitioning_left);
|
|
28
|
+
|
|
29
|
+
const parent = bvh.allocate_node();
|
|
30
|
+
|
|
31
|
+
const left_node = assemble_mask(bvh, leaves, partitioning_left);
|
|
32
|
+
const right_node = assemble_mask(bvh, leaves, partition_right);
|
|
33
|
+
|
|
34
|
+
bvh.node_assign_children(parent, left_node, right_node);
|
|
35
|
+
|
|
36
|
+
return parent;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @param {BVH} bvh
|
|
42
|
+
* @param {number} root
|
|
43
|
+
* @param {number[]} leaves
|
|
44
|
+
* @param {number} mask
|
|
45
|
+
*/
|
|
46
|
+
function rebuild_treelet(bvh, root, leaves, mask) {
|
|
47
|
+
|
|
48
|
+
let partitioning_left = scratch_pairings[mask];
|
|
49
|
+
let partition_right = mask & ~(partitioning_left);
|
|
50
|
+
|
|
51
|
+
bvh.node_assign_children(root,
|
|
52
|
+
assemble_mask(bvh, leaves, partitioning_left),
|
|
53
|
+
assemble_mask(bvh, leaves, partition_right),
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
*
|
|
59
|
+
* @param {BVH} bvh
|
|
60
|
+
* @param {number} root
|
|
61
|
+
* @param {number[]|Uint32Array} leaves
|
|
62
|
+
* @param {number} leaf_count
|
|
63
|
+
*/
|
|
64
|
+
function optimize_treelet(bvh, root, leaves, leaf_count) {
|
|
65
|
+
// console.log(`TREELET(${leaf_count}): ${leaves.slice(0, leaf_count).join(', ')}`); // DEBUG
|
|
66
|
+
|
|
67
|
+
// see "Fast Parallel Construction of High-Quality Bounding Volume Hierarchies", Algorithm 2
|
|
68
|
+
|
|
69
|
+
// Calculate surface area for each subset
|
|
70
|
+
for (let i = 0; i < leaf_count; i++) {
|
|
71
|
+
const leaf_0 = leaves[i];
|
|
72
|
+
for (let j = i + 1; j < leaf_count; j++) {
|
|
73
|
+
const leaf_1 = leaves[j];
|
|
74
|
+
|
|
75
|
+
const s = (1 << i) | (1 << j);
|
|
76
|
+
|
|
77
|
+
scratch_areas[s] = bvh.node_get_combined_surface_area(leaf_0, leaf_1)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Initialize costs of individual leaves
|
|
82
|
+
for (let i = 0; i < leaf_count; i++) {
|
|
83
|
+
scratch_cost[1 << i] = bvh.node_get_surface_area(leaves[i]);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Optimize every subset of leaves
|
|
87
|
+
for (let k = 2; k <= leaf_count; k++) {
|
|
88
|
+
for (let s = 1; s <= (1 << leaf_count) - 1; s++) {
|
|
89
|
+
if (bitCount(s) !== k) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Try each way of partitioning the leaves
|
|
94
|
+
let best_cost = Infinity;
|
|
95
|
+
let best_pairing = 0;
|
|
96
|
+
|
|
97
|
+
const delta = (s - 1) & s;
|
|
98
|
+
let p = (-delta) & s;
|
|
99
|
+
|
|
100
|
+
do {
|
|
101
|
+
const cost = scratch_cost[p] + scratch_cost[s ^ p];
|
|
102
|
+
|
|
103
|
+
if (cost < best_cost) {
|
|
104
|
+
best_cost = cost;
|
|
105
|
+
best_pairing = p;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
p = (p - delta) & s;
|
|
109
|
+
|
|
110
|
+
} while (p !== 0)
|
|
111
|
+
|
|
112
|
+
// Calculate final SAH cost (Equation 2)
|
|
113
|
+
scratch_cost[s] = scratch_areas[s] + best_cost;
|
|
114
|
+
scratch_pairings[s] = best_pairing;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// build tree
|
|
119
|
+
rebuild_treelet(bvh, root, leaves, (1 << leaf_count) - 1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
*
|
|
127
|
+
* @param {BVH} bvh
|
|
128
|
+
* @param {number} root
|
|
129
|
+
* @param {number} treelet_max_size
|
|
130
|
+
*/
|
|
131
|
+
function optimize_at_node(bvh, root, treelet_max_size) {
|
|
132
|
+
if (bvh.node_is_leaf(root)) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const left = bvh.node_get_child1(root);
|
|
137
|
+
const right = bvh.node_get_child2(root);
|
|
138
|
+
|
|
139
|
+
let treelet_size = 0;
|
|
140
|
+
|
|
141
|
+
if (left !== NULL_NODE) {
|
|
142
|
+
scratch_treelet[treelet_size++] = left;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (right !== NULL_NODE) {
|
|
146
|
+
scratch_treelet[treelet_size++] = right;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (treelet_size === 0) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
while (treelet_size < treelet_max_size) {
|
|
154
|
+
// pick node with the largest surface area
|
|
155
|
+
let best_node_index = -1;
|
|
156
|
+
let best_area = 0; //note that this is deliberate, expanding node with 0 area is pointless
|
|
157
|
+
|
|
158
|
+
for (let i = 0; i < treelet_size; i++) {
|
|
159
|
+
const n = scratch_treelet[i];
|
|
160
|
+
|
|
161
|
+
if (bvh.node_is_leaf(n)) {
|
|
162
|
+
// can't expand
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// TODO maintain list of areas instead of computing them every time
|
|
167
|
+
const area = bvh.node_get_surface_area(n);
|
|
168
|
+
if (area > best_area) {
|
|
169
|
+
best_area = area;
|
|
170
|
+
best_node_index = i;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (best_node_index === -1) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// expand candidate
|
|
179
|
+
const victim = scratch_treelet[best_node_index];
|
|
180
|
+
|
|
181
|
+
const c0 = bvh.node_get_child1(victim);
|
|
182
|
+
const c1 = bvh.node_get_child2(victim);
|
|
183
|
+
|
|
184
|
+
scratch_treelet[best_node_index] = c0;
|
|
185
|
+
scratch_treelet[treelet_size++] = c1;
|
|
186
|
+
|
|
187
|
+
bvh.release_node(victim);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (treelet_size <= 2) {
|
|
191
|
+
// nothing to do
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
optimize_treelet(bvh, root, scratch_treelet, treelet_size);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const CAME_FROM_TYPE_PARENT = 0;
|
|
199
|
+
const CAME_FROM_TYPE_CHILD_1 = 1;
|
|
200
|
+
const CAME_FROM_TYPE_CHILD_2 = 2;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Perform linear optimization across the tree, similar to rotations, but we support somewhat arbitrary depth and all possible permutations
|
|
204
|
+
* Note that the root does not move, but everything below the root is subject to change
|
|
205
|
+
* @see "Fast Parallel Construction of High-Quality Bounding Volume Hierarchies" by Kerras, NVIDIA 2013
|
|
206
|
+
* @param {BVH} bvh
|
|
207
|
+
* @param {number} root
|
|
208
|
+
* @param {number} [treelet_size]
|
|
209
|
+
*/
|
|
210
|
+
export function ebvh_optimize_treelet(bvh, root, treelet_size = 7) {
|
|
211
|
+
assert.isNonNegativeInteger(treelet_size, 'treelet_size');
|
|
212
|
+
assert.lessThanOrEqual(treelet_size, 8, 'limit is 8');
|
|
213
|
+
|
|
214
|
+
if (root === NULL_NODE) {
|
|
215
|
+
// special case
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (bvh.node_is_leaf(root)) {
|
|
220
|
+
// special case
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// we traverse depth-first using stack-less scheme
|
|
225
|
+
let came_from_node = root;
|
|
226
|
+
|
|
227
|
+
let came_from_type = CAME_FROM_TYPE_PARENT;
|
|
228
|
+
|
|
229
|
+
let node = bvh.node_get_child1(came_from_node);
|
|
230
|
+
if (node === NULL_NODE) {
|
|
231
|
+
node = bvh.node_get_child2(came_from_node);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (node === NULL_NODE) {
|
|
235
|
+
// no children, done
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const min_height = Math.ceil(Math.log2(treelet_size));
|
|
240
|
+
|
|
241
|
+
while (true) {
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
if (
|
|
245
|
+
came_from_type === CAME_FROM_TYPE_CHILD_2
|
|
246
|
+
&& bvh.node_get_height(node) >= min_height
|
|
247
|
+
) {
|
|
248
|
+
// only form treelets when moving up
|
|
249
|
+
optimize_at_node(bvh, node, treelet_size);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// only add to treelet when traversing up, not down
|
|
253
|
+
|
|
254
|
+
if (bvh.node_is_leaf(node)) {
|
|
255
|
+
|
|
256
|
+
assert.equal(came_from_type, CAME_FROM_TYPE_PARENT);
|
|
257
|
+
|
|
258
|
+
const parent = came_from_node;
|
|
259
|
+
const parent_child_1 = bvh.node_get_child1(parent);
|
|
260
|
+
|
|
261
|
+
if (parent_child_1 === node) {
|
|
262
|
+
came_from_type = CAME_FROM_TYPE_CHILD_1;
|
|
263
|
+
} else {
|
|
264
|
+
came_from_type = CAME_FROM_TYPE_CHILD_2;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
came_from_node = node;
|
|
268
|
+
|
|
269
|
+
node = parent;
|
|
270
|
+
} else if (came_from_type === CAME_FROM_TYPE_CHILD_2) {
|
|
271
|
+
// finishing traversal of this branch
|
|
272
|
+
came_from_node = node;
|
|
273
|
+
const parent = bvh.node_get_parent(node);
|
|
274
|
+
|
|
275
|
+
if (bvh.node_get_child1(parent) === node) {
|
|
276
|
+
came_from_type = CAME_FROM_TYPE_CHILD_1;
|
|
277
|
+
} else {
|
|
278
|
+
came_from_type = CAME_FROM_TYPE_CHILD_2;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (node === root) {
|
|
282
|
+
// traversed all the way back up
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
node = parent;
|
|
287
|
+
|
|
288
|
+
} else if (came_from_type === CAME_FROM_TYPE_CHILD_1) {
|
|
289
|
+
// traversing up from left child
|
|
290
|
+
const child2 = bvh.node_get_child2(node);
|
|
291
|
+
|
|
292
|
+
came_from_node = node;
|
|
293
|
+
|
|
294
|
+
if (child2 === NULL_NODE) {
|
|
295
|
+
// no right child, finish this branch
|
|
296
|
+
came_from_type = CAME_FROM_TYPE_CHILD_2; // indicate end
|
|
297
|
+
|
|
298
|
+
node = bvh.node_get_parent(node);
|
|
299
|
+
} else {
|
|
300
|
+
came_from_type = CAME_FROM_TYPE_PARENT;
|
|
301
|
+
node = child2;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
} else if (came_from_type === CAME_FROM_TYPE_PARENT) {
|
|
305
|
+
const child1 = bvh.node_get_child1(node);
|
|
306
|
+
const child2 = bvh.node_get_child1(node);
|
|
307
|
+
|
|
308
|
+
if (child1 !== NULL_NODE) {
|
|
309
|
+
came_from_type = CAME_FROM_TYPE_PARENT;
|
|
310
|
+
came_from_node = node;
|
|
311
|
+
node = child1;
|
|
312
|
+
} else if (child2 !== NULL_NODE) {
|
|
313
|
+
came_from_type = CAME_FROM_TYPE_PARENT;
|
|
314
|
+
came_from_node = node;
|
|
315
|
+
node = child2;
|
|
316
|
+
} else {
|
|
317
|
+
// this should not happen, as this would mean that node is empty and completely pointless
|
|
318
|
+
// we remove the node and traverse up
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
const parent_child1 = bvh.node_get_child1(came_from_node);
|
|
322
|
+
|
|
323
|
+
bvh.release_node(node);
|
|
324
|
+
|
|
325
|
+
if (parent_child1 === node) {
|
|
326
|
+
// we are left child
|
|
327
|
+
bvh.node_set_child1(came_from_node, NULL_NODE);
|
|
328
|
+
came_from_node = NULL_NODE;
|
|
329
|
+
came_from_type = CAME_FROM_TYPE_CHILD_1;
|
|
330
|
+
} else {
|
|
331
|
+
bvh.node_set_child2(came_from_node, NULL_NODE);
|
|
332
|
+
came_from_node = NULL_NODE;
|
|
333
|
+
came_from_type = CAME_FROM_TYPE_CHILD_2;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
node = came_from_node;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// optimize last collected treelet
|
|
345
|
+
optimize_at_node(bvh, root, treelet_size);
|
|
346
|
+
}
|