@woosh/meep-engine 2.122.2 → 2.122.3
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.js +4 -4
- package/src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.js +0 -11
- package/src/core/bvh2/bvh3/ebvh_build_hierarchy.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/ebvh_build_hierarchy.js +14 -15
- package/src/core/bvh2/bvh3/ebvh_build_hierarchy_radix.d.ts +11 -0
- package/src/core/bvh2/bvh3/ebvh_build_hierarchy_radix.d.ts.map +1 -0
- package/src/core/bvh2/bvh3/ebvh_build_hierarchy_radix.js +275 -0
- package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts.map +1 -1
- package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +1 -0
package/package.json
CHANGED
|
@@ -1051,6 +1051,8 @@ export class BVH {
|
|
|
1051
1051
|
* @param {number} child_2
|
|
1052
1052
|
*/
|
|
1053
1053
|
node_assign_children(parent, child_1, child_2) {
|
|
1054
|
+
this.node_set_combined_aabb(parent, child_1, child_2);
|
|
1055
|
+
|
|
1054
1056
|
this.node_set_child1(parent, child_1);
|
|
1055
1057
|
this.node_set_child2(parent, child_2);
|
|
1056
1058
|
|
|
@@ -1058,13 +1060,11 @@ export class BVH {
|
|
|
1058
1060
|
this.node_set_parent(child_2, parent);
|
|
1059
1061
|
|
|
1060
1062
|
this.node_set_height(parent,
|
|
1061
|
-
Math.max(
|
|
1063
|
+
1+ Math.max(
|
|
1062
1064
|
this.node_get_height(child_1),
|
|
1063
1065
|
this.node_get_height(child_2),
|
|
1064
|
-
)
|
|
1066
|
+
)
|
|
1065
1067
|
);
|
|
1066
|
-
|
|
1067
|
-
this.node_set_combined_aabb(parent, child_1, child_2);
|
|
1068
1068
|
}
|
|
1069
1069
|
|
|
1070
1070
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ebvh_build_for_geometry_morton.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.js"],"names":[],"mappings":"AAYA;;;;;;;;;GASG;AACH,oDAPW,GAAG,eACH,MAAM,EAAE,GAAC,WAAW,GAAC,WAAW,kBAChC,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,iBAClC,WAAW,WACX,KAAK,YACL,MAAM,
|
|
1
|
+
{"version":3,"file":"ebvh_build_for_geometry_morton.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.js"],"names":[],"mappings":"AAYA;;;;;;;;;GASG;AACH,oDAPW,GAAG,eACH,MAAM,EAAE,GAAC,WAAW,GAAC,WAAW,kBAChC,MAAM,EAAE,GAAC,YAAY,GAAC,YAAY,iBAClC,WAAW,WACX,KAAK,YACL,MAAM,QAsHhB;sBAvIqB,6BAA6B"}
|
|
@@ -131,18 +131,7 @@ export function ebvh_build_for_geometry_morton(
|
|
|
131
131
|
|
|
132
132
|
typed_array_copy(nodes, unprocessed_nodes);
|
|
133
133
|
|
|
134
|
-
// do long-distance swaps, starting high and coming down
|
|
135
|
-
for (let power = 5; power > Math.max(5 - quality, 1); power--) {
|
|
136
|
-
|
|
137
|
-
ebvh_nodes_sort_sah_local4(
|
|
138
|
-
bvh,
|
|
139
|
-
unprocessed_nodes,
|
|
140
|
-
0,
|
|
141
|
-
1 << power,
|
|
142
|
-
tri_count
|
|
143
|
-
);
|
|
144
134
|
|
|
145
|
-
}
|
|
146
135
|
|
|
147
136
|
|
|
148
137
|
// assign root
|
|
@@ -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":"AAIA;;;;;;;;;;;;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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { assert } from "../../assert.js";
|
|
2
|
-
import { max2 } from "../../math/max2.js";
|
|
3
2
|
import { NULL_NODE } from "./BVH.js";
|
|
4
3
|
import { ebvh_nodes_sort_sah_local4 } from "./ebvh_nodes_sort_sah_local4.js";
|
|
5
4
|
|
|
@@ -40,6 +39,19 @@ export function ebvh_build_hierarchy(
|
|
|
40
39
|
|
|
41
40
|
const sah_optimization_cycle_count = Math.floor(sah_optimization_level + sah_optimization_bias * current_construction_depth);
|
|
42
41
|
|
|
42
|
+
// do long-distance swaps, starting high and coming down
|
|
43
|
+
for (let power = 5; power > Math.max(5 - sah_optimization_cycle_count, 1); power--) {
|
|
44
|
+
|
|
45
|
+
ebvh_nodes_sort_sah_local4(
|
|
46
|
+
bvh,
|
|
47
|
+
unprocessed_nodes,
|
|
48
|
+
0,
|
|
49
|
+
1 << power,
|
|
50
|
+
unprocessed_node_count
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
43
55
|
for (let i = 0; i < sah_optimization_cycle_count; i++) {
|
|
44
56
|
|
|
45
57
|
// Sort intermediate nodes using small locality and SAH metric
|
|
@@ -65,20 +77,7 @@ export function ebvh_build_hierarchy(
|
|
|
65
77
|
|
|
66
78
|
const parent = node_pool[used_index++];
|
|
67
79
|
|
|
68
|
-
bvh.
|
|
69
|
-
|
|
70
|
-
bvh.node_set_parent(child_1, parent);
|
|
71
|
-
bvh.node_set_parent(child_2, parent);
|
|
72
|
-
|
|
73
|
-
bvh.node_set_child1(parent, child_1);
|
|
74
|
-
bvh.node_set_child2(parent, child_2);
|
|
75
|
-
|
|
76
|
-
bvh.node_set_height(parent,
|
|
77
|
-
1 + max2(
|
|
78
|
-
bvh.node_get_height(child_1),
|
|
79
|
-
bvh.node_get_height(child_2)
|
|
80
|
-
)
|
|
81
|
-
);
|
|
80
|
+
bvh.node_assign_children(parent, child_1, child_2);
|
|
82
81
|
|
|
83
82
|
unprocessed_nodes[added_nodes++] = parent;
|
|
84
83
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DO NOT USE, currently broken
|
|
3
|
+
* @param {BVH} bvh
|
|
4
|
+
* @param {number[]|Uint32Array} leaf_nodes
|
|
5
|
+
* @param {number[]} sorted_morton_codes
|
|
6
|
+
* @param {number} leaf_count
|
|
7
|
+
* @param {number[]} internal_nodes
|
|
8
|
+
* @returns {number} new root
|
|
9
|
+
*/
|
|
10
|
+
export function ebvh_build_hierarchy_radix(bvh: BVH, leaf_nodes: number[] | Uint32Array, sorted_morton_codes: number[], leaf_count: number, internal_nodes: number[]): number;
|
|
11
|
+
//# sourceMappingURL=ebvh_build_hierarchy_radix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ebvh_build_hierarchy_radix.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_build_hierarchy_radix.js"],"names":[],"mappings":"AA0MA;;;;;;;;GAQG;AACH,gDAPW,GAAG,cACH,MAAM,EAAE,GAAC,WAAW,uBACpB,MAAM,EAAE,cACR,MAAM,kBACN,MAAM,EAAE,GACN,MAAM,CAiElB"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { assert } from "../../assert.js";
|
|
2
|
+
import { clz32 } from "../../binary/clz32.js";
|
|
3
|
+
import { clamp } from "../../math/clamp.js";
|
|
4
|
+
import { NULL_NODE } from "./BVH.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @see "Thinking Parallel, Part III: Tree Construction on the GPU", 2012 by Tero Karras
|
|
9
|
+
*
|
|
10
|
+
* @param {number[]|Uint32Array} sortedMortonCodes
|
|
11
|
+
* @param {number} first
|
|
12
|
+
* @param {number} last
|
|
13
|
+
* @return {number}
|
|
14
|
+
*/
|
|
15
|
+
function find_split(
|
|
16
|
+
sortedMortonCodes,
|
|
17
|
+
first,
|
|
18
|
+
last
|
|
19
|
+
) {
|
|
20
|
+
// Identical Morton codes => split the range in the middle.
|
|
21
|
+
|
|
22
|
+
const firstCode = sortedMortonCodes[first];
|
|
23
|
+
const lastCode = sortedMortonCodes[last];
|
|
24
|
+
|
|
25
|
+
if (firstCode === lastCode) {
|
|
26
|
+
return (first + last) >>> 1;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Calculate the number of highest bits that are the same
|
|
30
|
+
// for all objects, using the count-leading-zeros intrinsic.
|
|
31
|
+
|
|
32
|
+
const commonPrefix = clz32(firstCode ^ lastCode);
|
|
33
|
+
|
|
34
|
+
// Use binary search to find where the next bit differs.
|
|
35
|
+
// Specifically, we are looking for the highest object that
|
|
36
|
+
// shares more than commonPrefix bits with the first one.
|
|
37
|
+
|
|
38
|
+
let split = first; // initial guess
|
|
39
|
+
let step = last - first;
|
|
40
|
+
|
|
41
|
+
do {
|
|
42
|
+
step = (step + 1) >>> 1; // exponential decrease
|
|
43
|
+
const newSplit = split + step; // proposed new position
|
|
44
|
+
|
|
45
|
+
if (newSplit < last) {
|
|
46
|
+
const splitCode = sortedMortonCodes[newSplit];
|
|
47
|
+
const splitPrefix = clz32(firstCode ^ splitCode);
|
|
48
|
+
if (splitPrefix > commonPrefix) {
|
|
49
|
+
split = newSplit; // accept proposal
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
while (step > 1);
|
|
54
|
+
|
|
55
|
+
return split;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @param indexA
|
|
61
|
+
* @param indexB
|
|
62
|
+
* @param elementCount
|
|
63
|
+
* @param mortonCodes
|
|
64
|
+
* @return {number}
|
|
65
|
+
* @see https://github.com/turanszkij/WickedEngine/blob/506749de321c2ab66fd33fbe41efb95afbbb7ff8/WickedEngine/shaders/bvh_hierarchyCS.hlsl#L28C1-L48C2
|
|
66
|
+
*/
|
|
67
|
+
function GetLongestCommonPrefix(indexA, indexB, elementCount, mortonCodes) {
|
|
68
|
+
assert.isNonNegativeInteger(indexA, 'indexA');
|
|
69
|
+
assert.isNonNegativeInteger(indexB, 'indexB');
|
|
70
|
+
|
|
71
|
+
if (indexA >= elementCount || indexB >= elementCount) {
|
|
72
|
+
return -1;
|
|
73
|
+
} else {
|
|
74
|
+
const mortonCodeA = mortonCodes[indexA];
|
|
75
|
+
const mortonCodeB = mortonCodes[indexB];
|
|
76
|
+
if (mortonCodeA !== mortonCodeB) {
|
|
77
|
+
return clz32(mortonCodeA ^ mortonCodeB);
|
|
78
|
+
} else {
|
|
79
|
+
// TODO: Technically this should be primitive ID
|
|
80
|
+
return clz32(indexA ^ indexB) + 31;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @see https://github.com/turanszkij/WickedEngine/blob/506749de321c2ab66fd33fbe41efb95afbbb7ff8/WickedEngine/shaders/bvh_hierarchyCS.hlsl#L28C1-L48C2
|
|
87
|
+
* @param {number[]|Uint32Array} output
|
|
88
|
+
* @param {number[]} sortedMortonCodes
|
|
89
|
+
* @param {number} numTriangles
|
|
90
|
+
* @param {number} idx
|
|
91
|
+
*/
|
|
92
|
+
function determineRangeW(output, sortedMortonCodes, numTriangles, idx) {
|
|
93
|
+
if (idx === 0) {
|
|
94
|
+
// root
|
|
95
|
+
output[0] = 0;
|
|
96
|
+
output[1] = numTriangles - 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let d = GetLongestCommonPrefix(idx, idx + 1, numTriangles, sortedMortonCodes) - GetLongestCommonPrefix(idx, idx - 1, numTriangles, sortedMortonCodes);
|
|
101
|
+
d = clamp(d, -1, 1);
|
|
102
|
+
|
|
103
|
+
let minPrefix = GetLongestCommonPrefix(idx, idx - d, numTriangles, sortedMortonCodes);
|
|
104
|
+
|
|
105
|
+
// TODO: Consider starting this at a higher number
|
|
106
|
+
let maxLength = 2;
|
|
107
|
+
while (GetLongestCommonPrefix(idx, idx + maxLength * d, numTriangles, sortedMortonCodes) > minPrefix) {
|
|
108
|
+
maxLength <<= 2;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let length = 0;
|
|
112
|
+
for (let t = maxLength >>> 1; t > 0; t >>>= 1) {
|
|
113
|
+
if (GetLongestCommonPrefix(idx, idx + (length + t) * d, numTriangles, sortedMortonCodes) > minPrefix) {
|
|
114
|
+
length = length + t;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let j = idx + length * d;
|
|
119
|
+
|
|
120
|
+
output[0] = Math.min(idx, j);
|
|
121
|
+
output[1] = Math.max(idx, j);
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @see https://github.com/mbartling/cuda-bvh/blob/7f2f98d9d29956c3559632e59104ba66f31f80b8/kernels/bvh.cu#L276C1-L352C2
|
|
127
|
+
* @param {number[]|Uint32Array} output
|
|
128
|
+
* @param {number[]} sortedMortonCodes
|
|
129
|
+
* @param {number} numTriangles
|
|
130
|
+
* @param {number} idx
|
|
131
|
+
*/
|
|
132
|
+
function determineRange(output, sortedMortonCodes, numTriangles, idx) {
|
|
133
|
+
|
|
134
|
+
//determine the range of keys covered by each internal node (as well as its children)
|
|
135
|
+
//direction is found by looking at the neighboring keys ki-1 , ki , ki+1
|
|
136
|
+
//the index is either the beginning of the range or the end of the range
|
|
137
|
+
let direction = 0;
|
|
138
|
+
let common_prefix_with_left = 0;
|
|
139
|
+
let common_prefix_with_right = 0;
|
|
140
|
+
|
|
141
|
+
common_prefix_with_right = clz32(sortedMortonCodes[idx] ^ sortedMortonCodes[idx + 1]);
|
|
142
|
+
|
|
143
|
+
if (idx === 0) {
|
|
144
|
+
common_prefix_with_left = -1;
|
|
145
|
+
} else {
|
|
146
|
+
common_prefix_with_left = clz32(sortedMortonCodes[idx] ^ sortedMortonCodes[idx - 1]);
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
direction = ((common_prefix_with_right - common_prefix_with_left) > 0) ? 1 : -1;
|
|
151
|
+
|
|
152
|
+
let min_prefix_range = 0;
|
|
153
|
+
|
|
154
|
+
if (idx === 0) {
|
|
155
|
+
min_prefix_range = -1;
|
|
156
|
+
|
|
157
|
+
} else {
|
|
158
|
+
min_prefix_range = clz32(sortedMortonCodes[idx] ^ sortedMortonCodes[idx - direction]);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let lmax = 2;
|
|
162
|
+
let next_key = idx + lmax * direction;
|
|
163
|
+
|
|
164
|
+
while ((next_key >= 0) && (next_key < numTriangles) && (clz32(sortedMortonCodes[idx] ^ sortedMortonCodes[next_key]) > min_prefix_range)) {
|
|
165
|
+
lmax *= 2;
|
|
166
|
+
next_key = idx + lmax * direction;
|
|
167
|
+
}
|
|
168
|
+
//find the other end using binary search
|
|
169
|
+
let l = 0;
|
|
170
|
+
|
|
171
|
+
do {
|
|
172
|
+
lmax = (lmax + 1) >> 1; // exponential decrease
|
|
173
|
+
const new_val = idx + (l + lmax) * direction;
|
|
174
|
+
|
|
175
|
+
if (new_val >= 0 && new_val < numTriangles) {
|
|
176
|
+
const Code = sortedMortonCodes[new_val];
|
|
177
|
+
const Prefix = clz32(sortedMortonCodes[idx] ^ Code);
|
|
178
|
+
if (Prefix > min_prefix_range) {
|
|
179
|
+
l = l + lmax;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
} while (lmax > 1);
|
|
183
|
+
|
|
184
|
+
const j = idx + l * direction;
|
|
185
|
+
|
|
186
|
+
let left = 0;
|
|
187
|
+
let right = 0;
|
|
188
|
+
|
|
189
|
+
if (idx < j) {
|
|
190
|
+
left = idx;
|
|
191
|
+
right = j;
|
|
192
|
+
} else {
|
|
193
|
+
left = j;
|
|
194
|
+
right = idx;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// printf("idx : (%d) returning range (%d, %d) \n" , idx , left, right);
|
|
198
|
+
|
|
199
|
+
output[0] = left
|
|
200
|
+
output[1] = right;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* DO NOT USE, currently broken
|
|
205
|
+
* @param {BVH} bvh
|
|
206
|
+
* @param {number[]|Uint32Array} leaf_nodes
|
|
207
|
+
* @param {number[]} sorted_morton_codes
|
|
208
|
+
* @param {number} leaf_count
|
|
209
|
+
* @param {number[]} internal_nodes
|
|
210
|
+
* @returns {number} new root
|
|
211
|
+
*/
|
|
212
|
+
export function ebvh_build_hierarchy_radix(
|
|
213
|
+
bvh,
|
|
214
|
+
leaf_nodes,
|
|
215
|
+
sorted_morton_codes,
|
|
216
|
+
leaf_count,
|
|
217
|
+
internal_nodes,
|
|
218
|
+
) {
|
|
219
|
+
console.warn("IMPLEMENTATION IS INCOMPLETE, DO NOT USE")
|
|
220
|
+
|
|
221
|
+
assert.isNonNegativeInteger(leaf_count, 'leaf_count');
|
|
222
|
+
|
|
223
|
+
// Construct leaf nodes.
|
|
224
|
+
// Note: This step can be avoided by storing
|
|
225
|
+
// the tree in a slightly different way.
|
|
226
|
+
|
|
227
|
+
const range = new Uint32Array(2);
|
|
228
|
+
|
|
229
|
+
// Construct internal nodes.
|
|
230
|
+
for (let idx = 0; idx < leaf_count - 1; idx++) // in parallel
|
|
231
|
+
{
|
|
232
|
+
// Find out which range of objects the node corresponds to.
|
|
233
|
+
// (This is where the magic happens!)
|
|
234
|
+
|
|
235
|
+
determineRange(range, sorted_morton_codes, leaf_count, idx);
|
|
236
|
+
|
|
237
|
+
const first = range[0];
|
|
238
|
+
const last = range[1];
|
|
239
|
+
|
|
240
|
+
// Determine where to split the range.
|
|
241
|
+
|
|
242
|
+
const split = find_split(sorted_morton_codes, first, last);
|
|
243
|
+
assert.isNonNegativeInteger(split, 'split');
|
|
244
|
+
|
|
245
|
+
// Select childA.
|
|
246
|
+
|
|
247
|
+
let childA;
|
|
248
|
+
if (split === first) {
|
|
249
|
+
childA = leaf_nodes[split];
|
|
250
|
+
} else {
|
|
251
|
+
childA = internal_nodes[split];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Select childB.
|
|
255
|
+
|
|
256
|
+
let childB;
|
|
257
|
+
if (split + 1 === last) {
|
|
258
|
+
childB = leaf_nodes[split + 1];
|
|
259
|
+
} else {
|
|
260
|
+
childB = internal_nodes[split + 1];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Record parent-child relationships.
|
|
264
|
+
const parent = internal_nodes[idx];
|
|
265
|
+
|
|
266
|
+
bvh.node_assign_children(parent, childA, childB);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Node 0 is the root.
|
|
270
|
+
const root = internal_nodes[0];
|
|
271
|
+
|
|
272
|
+
bvh.node_set_parent(root, NULL_NODE);
|
|
273
|
+
|
|
274
|
+
return root;
|
|
275
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ebvh_optimize_treelet.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_optimize_treelet.js"],"names":[],"mappings":"AAuNA;;;;;;;GAOG;AACH,2CAJW,GAAG,SACH,MAAM,iBACN,MAAM,
|
|
1
|
+
{"version":3,"file":"ebvh_optimize_treelet.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_optimize_treelet.js"],"names":[],"mappings":"AAuNA;;;;;;;GAOG;AACH,2CAJW,GAAG,SACH,MAAM,iBACN,MAAM,QA+IhB"}
|