|
5 | 5 | import { Box3, Vector3 } from 'three'; |
6 | 6 | import { partition, nthElement } from './bvhUtil'; |
7 | 7 |
|
8 | | -const size = new Vector3; |
| 8 | +const size = new Vector3(); |
9 | 9 |
|
10 | | -function maximumExtent(box3) { |
11 | | - box3.getSize(size); |
12 | | - if (size.x > size.z) { |
13 | | - return size.x > size.y ? 'x' : 'y'; |
14 | | - } else { |
15 | | - return size.z > size.y ? 'z' : 'y'; |
16 | | - } |
| 10 | +export function bvhAccel(geometry, materialIndices) { |
| 11 | + const primitiveInfo = makePrimitiveInfo(geometry, materialIndices); |
| 12 | + const node = recursiveBuild(primitiveInfo, 0, primitiveInfo.length); |
| 13 | + |
| 14 | + return node; |
17 | 15 | } |
18 | 16 |
|
19 | | -function boxOffset(box3, dim, v) { |
20 | | - let offset = v[dim] - box3.min[dim]; |
| 17 | +export function flattenBvh(bvh) { |
| 18 | + const flat = []; |
| 19 | + const isBounds = []; |
21 | 20 |
|
22 | | - if (box3.max[dim] > box3.min[dim]){ |
23 | | - offset /= box3.max[dim] - box3.min[dim]; |
24 | | - } |
| 21 | + const splitAxisMap = { |
| 22 | + x: 0, |
| 23 | + y: 1, |
| 24 | + z: 2 |
| 25 | + }; |
25 | 26 |
|
26 | | - return offset; |
27 | | -} |
| 27 | + let maxDepth = 1; |
| 28 | + const traverse = (node, depth = 1) => { |
28 | 29 |
|
29 | | -function surfaceArea(box3) { |
30 | | - box3.getSize(size); |
31 | | - return 2 * (size.x * size.z + size.x * size.y + size.z * size.y); |
| 30 | + maxDepth = Math.max(depth, maxDepth); |
| 31 | + |
| 32 | + if (node.primitives) { |
| 33 | + for (let i = 0; i < node.primitives.length; i++) { |
| 34 | + const p = node.primitives[i]; |
| 35 | + flat.push( |
| 36 | + p.indices[0], p.indices[1], p.indices[2], node.primitives.length, |
| 37 | + p.faceNormal.x, p.faceNormal.y, p.faceNormal.z, p.materialIndex |
| 38 | + ); |
| 39 | + isBounds.push(false); |
| 40 | + } |
| 41 | + } else { |
| 42 | + const bounds = node.bounds; |
| 43 | + |
| 44 | + flat.push( |
| 45 | + bounds.min.x, bounds.min.y, bounds.min.z, splitAxisMap[node.splitAxis], |
| 46 | + bounds.max.x, bounds.max.y, bounds.max.z, null // pointer to second shild |
| 47 | + ); |
| 48 | + |
| 49 | + const i = flat.length - 1; |
| 50 | + isBounds.push(true); |
| 51 | + |
| 52 | + traverse(node.child0, depth + 1); |
| 53 | + flat[i] = flat.length / 4; // pointer to second child |
| 54 | + traverse(node.child1, depth + 1); |
| 55 | + } |
| 56 | + }; |
| 57 | + |
| 58 | + traverse(bvh); |
| 59 | + |
| 60 | + const buffer = new ArrayBuffer(4 * flat.length); |
| 61 | + const floatView = new Float32Array(buffer); |
| 62 | + const intView = new Int32Array(buffer); |
| 63 | + |
| 64 | + for (let i = 0; i < isBounds.length; i++) { |
| 65 | + let k = 8 * i; |
| 66 | + |
| 67 | + if (isBounds[i]) { |
| 68 | + floatView[k] = flat[k]; |
| 69 | + floatView[k + 1] = flat[k + 1]; |
| 70 | + floatView[k + 2] = flat[k + 2]; |
| 71 | + intView[k + 3] = flat[k + 3]; |
| 72 | + } else { |
| 73 | + intView[k] = flat[k]; |
| 74 | + intView[k + 1] = flat[k + 1]; |
| 75 | + intView[k + 2] = flat[k + 2]; |
| 76 | + intView[k + 3] = -flat[k + 3]; // negative signals to shader that this node is a triangle |
| 77 | + } |
| 78 | + |
| 79 | + floatView[k + 4] = flat[k + 4]; |
| 80 | + floatView[k + 5] = flat[k + 5]; |
| 81 | + floatView[k + 6] = flat[k + 6]; |
| 82 | + intView[k + 7] = flat[k + 7]; |
| 83 | + } |
| 84 | + |
| 85 | + return { |
| 86 | + maxDepth, |
| 87 | + count: flat.length / 4, |
| 88 | + buffer: floatView |
| 89 | + }; |
32 | 90 | } |
33 | 91 |
|
34 | 92 | function makePrimitiveInfo(geometry, materialIndices) { |
@@ -68,22 +126,6 @@ function makePrimitiveInfo(geometry, materialIndices) { |
68 | 126 | return primitiveInfo; |
69 | 127 | } |
70 | 128 |
|
71 | | -function makeLeafNode(primitives, bounds) { |
72 | | - return { |
73 | | - primitives, |
74 | | - bounds |
75 | | - }; |
76 | | -} |
77 | | - |
78 | | -function makeInteriorNode(splitAxis, child0, child1) { |
79 | | - return { |
80 | | - child0, |
81 | | - child1, |
82 | | - bounds: new Box3().union(child0.bounds).union(child1.bounds), |
83 | | - splitAxis, |
84 | | - }; |
85 | | -} |
86 | | - |
87 | 129 | function recursiveBuild(primitiveInfo, start, end) { |
88 | 130 | const bounds = new Box3(); |
89 | 131 | for (let i = start; i < end; i++) { |
@@ -177,84 +219,42 @@ function recursiveBuild(primitiveInfo, start, end) { |
177 | 219 | } |
178 | 220 | } |
179 | 221 |
|
180 | | -export function bvhAccel(geometry, materialIndices) { |
181 | | - const primitiveInfo = makePrimitiveInfo(geometry, materialIndices); |
182 | | - const node = recursiveBuild(primitiveInfo, 0, primitiveInfo.length); |
183 | | - |
184 | | - return node; |
185 | | -} |
186 | | - |
187 | | -export function flattenBvh(bvh) { |
188 | | - const flat = []; |
189 | | - const isBounds = []; |
190 | | - |
191 | | - const splitAxisMap = { |
192 | | - x: 0, |
193 | | - y: 1, |
194 | | - z: 2 |
| 222 | +function makeLeafNode(primitives, bounds) { |
| 223 | + return { |
| 224 | + primitives, |
| 225 | + bounds |
195 | 226 | }; |
| 227 | +} |
196 | 228 |
|
197 | | - let maxDepth = 1; |
198 | | - const traverse = (node, depth = 1) => { |
199 | | - |
200 | | - maxDepth = Math.max(depth, maxDepth); |
201 | | - |
202 | | - if (node.primitives) { |
203 | | - for (let i = 0; i < node.primitives.length; i++) { |
204 | | - const p = node.primitives[i]; |
205 | | - flat.push( |
206 | | - p.indices[0], p.indices[1], p.indices[2], node.primitives.length, |
207 | | - p.faceNormal.x, p.faceNormal.y, p.faceNormal.z, p.materialIndex |
208 | | - ); |
209 | | - isBounds.push(false); |
210 | | - } |
211 | | - } else { |
212 | | - const bounds = node.bounds; |
213 | | - |
214 | | - flat.push( |
215 | | - bounds.min.x, bounds.min.y, bounds.min.z, splitAxisMap[node.splitAxis], |
216 | | - bounds.max.x, bounds.max.y, bounds.max.z, null // pointer to second shild |
217 | | - ); |
218 | | - |
219 | | - const i = flat.length - 1; |
220 | | - isBounds.push(true); |
221 | | - |
222 | | - traverse(node.child0, depth + 1); |
223 | | - flat[i] = flat.length / 4; // pointer to second child |
224 | | - traverse(node.child1, depth + 1); |
225 | | - } |
| 229 | +function makeInteriorNode(splitAxis, child0, child1) { |
| 230 | + return { |
| 231 | + child0, |
| 232 | + child1, |
| 233 | + bounds: new Box3().union(child0.bounds).union(child1.bounds), |
| 234 | + splitAxis, |
226 | 235 | }; |
| 236 | +} |
227 | 237 |
|
228 | | - traverse(bvh); |
229 | | - |
230 | | - const buffer = new ArrayBuffer(4 * flat.length); |
231 | | - const floatView = new Float32Array(buffer); |
232 | | - const intView = new Int32Array(buffer); |
233 | | - |
234 | | - for (let i = 0; i < isBounds.length; i++) { |
235 | | - let k = 8 * i; |
| 238 | +function maximumExtent(box3) { |
| 239 | + box3.getSize(size); |
| 240 | + if (size.x > size.z) { |
| 241 | + return size.x > size.y ? 'x' : 'y'; |
| 242 | + } else { |
| 243 | + return size.z > size.y ? 'z' : 'y'; |
| 244 | + } |
| 245 | +} |
236 | 246 |
|
237 | | - if (isBounds[i]) { |
238 | | - floatView[k] = flat[k]; |
239 | | - floatView[k + 1] = flat[k + 1]; |
240 | | - floatView[k + 2] = flat[k + 2]; |
241 | | - intView[k + 3] = flat[k + 3]; |
242 | | - } else { |
243 | | - intView[k] = flat[k]; |
244 | | - intView[k + 1] = flat[k + 1]; |
245 | | - intView[k + 2] = flat[k + 2]; |
246 | | - intView[k + 3] = -flat[k + 3]; // negative signals to shader that this node is a triangle |
247 | | - } |
| 247 | +function boxOffset(box3, dim, v) { |
| 248 | + let offset = v[dim] - box3.min[dim]; |
248 | 249 |
|
249 | | - floatView[k + 4] = flat[k + 4]; |
250 | | - floatView[k + 5] = flat[k + 5]; |
251 | | - floatView[k + 6] = flat[k + 6]; |
252 | | - intView[k + 7] = flat[k + 7]; |
| 250 | + if (box3.max[dim] > box3.min[dim]){ |
| 251 | + offset /= box3.max[dim] - box3.min[dim]; |
253 | 252 | } |
254 | 253 |
|
255 | | - return { |
256 | | - maxDepth, |
257 | | - count: flat.length / 4, |
258 | | - buffer: floatView |
259 | | - }; |
| 254 | + return offset; |
| 255 | +} |
| 256 | + |
| 257 | +function surfaceArea(box3) { |
| 258 | + box3.getSize(size); |
| 259 | + return 2 * (size.x * size.z + size.x * size.y + size.z * size.y); |
260 | 260 | } |
0 commit comments