@multiplekex/shallot 0.2.5 → 0.3.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.
Files changed (41) hide show
  1. package/package.json +1 -1
  2. package/src/core/component.ts +1 -1
  3. package/src/core/index.ts +1 -13
  4. package/src/core/math.ts +186 -0
  5. package/src/core/state.ts +1 -1
  6. package/src/core/xml.ts +56 -41
  7. package/src/extras/orbit/index.ts +1 -1
  8. package/src/extras/text/index.ts +10 -65
  9. package/src/extras/{water.ts → water/index.ts} +59 -4
  10. package/src/standard/raster/batch.ts +149 -0
  11. package/src/standard/raster/forward.ts +832 -0
  12. package/src/standard/raster/index.ts +146 -472
  13. package/src/standard/raster/shadow.ts +408 -0
  14. package/src/standard/raytracing/bvh/blas.ts +335 -87
  15. package/src/standard/raytracing/bvh/radix.ts +225 -228
  16. package/src/standard/raytracing/bvh/refit.ts +711 -0
  17. package/src/standard/raytracing/bvh/structs.ts +0 -55
  18. package/src/standard/raytracing/bvh/tlas.ts +153 -141
  19. package/src/standard/raytracing/bvh/traverse.ts +72 -64
  20. package/src/standard/raytracing/index.ts +233 -204
  21. package/src/standard/raytracing/instance.ts +30 -18
  22. package/src/standard/raytracing/ray.ts +1 -1
  23. package/src/standard/raytracing/shaders.ts +23 -40
  24. package/src/standard/render/camera.ts +10 -28
  25. package/src/standard/render/data.ts +1 -1
  26. package/src/standard/render/index.ts +68 -12
  27. package/src/standard/render/light.ts +2 -2
  28. package/src/standard/render/mesh.ts +404 -0
  29. package/src/standard/render/overlay.ts +5 -2
  30. package/src/standard/render/postprocess.ts +263 -267
  31. package/src/standard/render/surface/index.ts +81 -12
  32. package/src/standard/render/surface/shaders.ts +265 -11
  33. package/src/standard/render/surface/structs.ts +10 -0
  34. package/src/standard/tween/tween.ts +44 -115
  35. package/src/standard/render/mesh/box.ts +0 -20
  36. package/src/standard/render/mesh/index.ts +0 -315
  37. package/src/standard/render/mesh/plane.ts +0 -11
  38. package/src/standard/render/mesh/sphere.ts +0 -40
  39. package/src/standard/render/mesh/unified.ts +0 -96
  40. package/src/standard/render/surface/compile.ts +0 -65
  41. package/src/standard/render/surface/noise.ts +0 -58
@@ -1,6 +1,7 @@
1
1
  import type { Vec3, BVHNode, MortonPair, AABB } from "./structs";
2
- import { LEAF_FLAG, isLeaf, leafIndex } from "./structs";
2
+ import { LEAF_FLAG, isLeaf, leafIndex, INVALID_NODE } from "./structs";
3
3
  import type { MeshData } from "../../render/mesh";
4
+ import { meshCount } from "../../render/mesh";
4
5
 
5
6
  export interface BLASTriangle {
6
7
  v0: Vec3;
@@ -14,18 +15,13 @@ export interface BLASTriangle {
14
15
  export interface BLASData {
15
16
  nodes: BVHNode[];
16
17
  sortedTriIds: number[];
18
+ sortedPairs: MortonPair[];
19
+ parents: number[];
17
20
  aabbMin: Vec3;
18
21
  aabbMax: Vec3;
19
22
  triCount: number;
20
23
  }
21
24
 
22
- export interface BLASMeta {
23
- nodeOffset: number;
24
- triIdOffset: number;
25
- nodeCount: number;
26
- triCount: number;
27
- }
28
-
29
25
  export interface BLASAtlas {
30
26
  blasData: Map<number, BLASData>;
31
27
  nodesBuffer: GPUBuffer;
@@ -34,6 +30,11 @@ export interface BLASAtlas {
34
30
  trianglesBuffer: GPUBuffer;
35
31
  triangles: Map<number, BLASTriangle[]>;
36
32
  shapeAABBs: GPUBuffer;
33
+ treeNodesBuffer: GPUBuffer;
34
+ parentIndicesBuffer: GPUBuffer;
35
+ baseTrianglesBuffer: GPUBuffer;
36
+ boundsFlagsBuffer: GPUBuffer;
37
+ metas: BLASMeta[];
37
38
  }
38
39
 
39
40
  function vec3(x: number, y: number, z: number): Vec3 {
@@ -406,8 +407,6 @@ function propagateBounds(
406
407
  const boundsFlags = new Array(n - 1).fill(0);
407
408
 
408
409
  for (let leafIdx = 0; leafIdx < n; leafIdx++) {
409
- const tri = triangles[pairs[leafIdx].triangleId];
410
-
411
410
  let current = leafIdx;
412
411
  let isLeafNode = true;
413
412
 
@@ -466,6 +465,8 @@ export function buildShapeBLAS(triangles: BLASTriangle[]): BLASData {
466
465
  return {
467
466
  nodes: [],
468
467
  sortedTriIds: [],
468
+ sortedPairs: [],
469
+ parents: [],
469
470
  aabbMin: vec3(0, 0, 0),
470
471
  aabbMax: vec3(0, 0, 0),
471
472
  triCount: 0,
@@ -478,6 +479,8 @@ export function buildShapeBLAS(triangles: BLASTriangle[]): BLASData {
478
479
  return {
479
480
  nodes: [],
480
481
  sortedTriIds: [0],
482
+ sortedPairs: [{ code: 0, triangleId: 0 }],
483
+ parents: [-1],
481
484
  aabbMin: bounds.min,
482
485
  aabbMax: bounds.max,
483
486
  triCount: 1,
@@ -497,114 +500,293 @@ export function buildShapeBLAS(triangles: BLASTriangle[]): BLASData {
497
500
  return {
498
501
  nodes,
499
502
  sortedTriIds,
503
+ sortedPairs,
504
+ parents,
500
505
  aabbMin: rootBounds.min,
501
506
  aabbMax: rootBounds.max,
502
507
  triCount,
503
508
  };
504
509
  }
505
510
 
506
- function validateBLASBounds(blas: BLASData, triangles: BLASTriangle[]): boolean {
507
- if (blas.triCount === 0) return true;
508
-
509
- const epsilon = 1e-5;
511
+ export interface BVH4Node {
512
+ children: [number, number, number, number];
513
+ bounds: [AABB, AABB, AABB, AABB];
514
+ }
510
515
 
511
- for (const tri of triangles) {
512
- const v0 = tri.v0;
513
- const v1 = vec3Add(v0, tri.e1);
514
- const v2 = vec3Add(v0, tri.e2);
516
+ function emptyAABB(): AABB {
517
+ return { min: vec3(1e30, 1e30, 1e30), max: vec3(-1e30, -1e30, -1e30) };
518
+ }
515
519
 
516
- for (const v of [v0, v1, v2]) {
517
- if (
518
- v.x < blas.aabbMin.x - epsilon ||
519
- v.y < blas.aabbMin.y - epsilon ||
520
- v.z < blas.aabbMin.z - epsilon ||
521
- v.x > blas.aabbMax.x + epsilon ||
522
- v.y > blas.aabbMax.y + epsilon ||
523
- v.z > blas.aabbMax.z + epsilon
524
- ) {
525
- return false;
526
- }
520
+ function computeDepths(nodes: BVHNode[], parents: number[], n: number): number[] {
521
+ const depths = new Array<number>(nodes.length).fill(0);
522
+ for (let i = 0; i < nodes.length; i++) {
523
+ let depth = 0;
524
+ let current = i;
525
+ while (current !== 0) {
526
+ const parent = parents[n + current];
527
+ if (parent === -1 || parent === undefined) break;
528
+ current = parent;
529
+ depth++;
527
530
  }
531
+ depths[i] = depth;
528
532
  }
529
-
530
- return true;
533
+ return depths;
531
534
  }
532
535
 
533
- function validateBLASNodes(blas: BLASData): { valid: boolean; errors: string[] } {
534
- const errors: string[] = [];
536
+ function getChildBounds(
537
+ child: number,
538
+ nodes: BVHNode[],
539
+ triangles: BLASTriangle[],
540
+ sortedPairs: MortonPair[]
541
+ ): AABB {
542
+ if (isLeaf(child)) {
543
+ const tri = triangles[sortedPairs[leafIndex(child)].triangleId];
544
+ return getTriangleBounds(tri);
545
+ }
546
+ const node = nodes[child];
547
+ return { min: node.min, max: node.max };
548
+ }
535
549
 
536
- if (blas.triCount <= 1) {
537
- return { valid: true, errors: [] };
550
+ export function collapseToBVH4(
551
+ bvh2Nodes: BVHNode[],
552
+ triCount: number,
553
+ sortedPairs: MortonPair[],
554
+ triangles: BLASTriangle[],
555
+ parents: number[]
556
+ ): BVH4Node[] {
557
+ if (triCount === 0) {
558
+ return [];
538
559
  }
539
560
 
540
- const expectedNodes = blas.triCount - 1;
541
- if (blas.nodes.length !== expectedNodes) {
542
- errors.push(`Expected ${expectedNodes} nodes, got ${blas.nodes.length}`);
561
+ if (triCount === 1) {
562
+ const bounds = getTriangleBounds(triangles[sortedPairs[0].triangleId]);
563
+ return [
564
+ {
565
+ children: [LEAF_FLAG | 0, INVALID_NODE, INVALID_NODE, INVALID_NODE],
566
+ bounds: [bounds, emptyAABB(), emptyAABB(), emptyAABB()],
567
+ },
568
+ ];
543
569
  }
544
570
 
545
- for (let i = 0; i < blas.nodes.length; i++) {
546
- const node = blas.nodes[i];
571
+ if (triCount === 2) {
572
+ const bounds0 = getTriangleBounds(triangles[sortedPairs[0].triangleId]);
573
+ const bounds1 = getTriangleBounds(triangles[sortedPairs[1].triangleId]);
574
+ const node = bvh2Nodes[0];
575
+ return [
576
+ {
577
+ children: [node.leftChild, node.rightChild, INVALID_NODE, INVALID_NODE],
578
+ bounds: [bounds0, bounds1, emptyAABB(), emptyAABB()],
579
+ },
580
+ ];
581
+ }
547
582
 
548
- if (node.min.x > node.max.x || node.min.y > node.max.y || node.min.z > node.max.z) {
549
- errors.push(`Node ${i} has invalid bounds: min > max`);
550
- }
583
+ const n = triCount;
584
+ const depths = computeDepths(bvh2Nodes, parents, n);
585
+ const bvh4Nodes: BVH4Node[] = new Array(bvh2Nodes.length);
551
586
 
587
+ for (let i = 0; i < bvh2Nodes.length; i++) {
588
+ const depth = depths[i];
589
+ const node = bvh2Nodes[i];
552
590
  const left = node.leftChild;
553
591
  const right = node.rightChild;
554
592
 
555
- if (isLeaf(left)) {
556
- const idx = leafIndex(left);
557
- if (idx >= blas.triCount) {
558
- errors.push(`Node ${i} left child leaf index ${idx} >= triCount ${blas.triCount}`);
559
- }
593
+ const out: BVH4Node = {
594
+ children: [INVALID_NODE, INVALID_NODE, INVALID_NODE, INVALID_NODE],
595
+ bounds: [emptyAABB(), emptyAABB(), emptyAABB(), emptyAABB()],
596
+ };
597
+
598
+ if ((depth & 1) !== 0) {
599
+ out.children[0] = left;
600
+ out.bounds[0] = getChildBounds(left, bvh2Nodes, triangles, sortedPairs);
601
+ out.children[1] = right;
602
+ out.bounds[1] = getChildBounds(right, bvh2Nodes, triangles, sortedPairs);
560
603
  } else {
561
- if (left >= blas.nodes.length) {
562
- errors.push(`Node ${i} left child ${left} >= node count ${blas.nodes.length}`);
563
- }
564
- }
604
+ let slot = 0;
565
605
 
566
- if (isLeaf(right)) {
567
- const idx = leafIndex(right);
568
- if (idx >= blas.triCount) {
569
- errors.push(`Node ${i} right child leaf index ${idx} >= triCount ${blas.triCount}`);
606
+ if (isLeaf(left)) {
607
+ out.children[slot] = left;
608
+ out.bounds[slot] = getChildBounds(left, bvh2Nodes, triangles, sortedPairs);
609
+ slot++;
610
+ } else {
611
+ const leftNode = bvh2Nodes[left];
612
+ out.children[slot] = leftNode.leftChild;
613
+ out.bounds[slot] = getChildBounds(
614
+ leftNode.leftChild,
615
+ bvh2Nodes,
616
+ triangles,
617
+ sortedPairs
618
+ );
619
+ slot++;
620
+ out.children[slot] = leftNode.rightChild;
621
+ out.bounds[slot] = getChildBounds(
622
+ leftNode.rightChild,
623
+ bvh2Nodes,
624
+ triangles,
625
+ sortedPairs
626
+ );
627
+ slot++;
570
628
  }
571
- } else {
572
- if (right >= blas.nodes.length) {
573
- errors.push(`Node ${i} right child ${right} >= node count ${blas.nodes.length}`);
629
+
630
+ if (isLeaf(right)) {
631
+ out.children[slot] = right;
632
+ out.bounds[slot] = getChildBounds(right, bvh2Nodes, triangles, sortedPairs);
633
+ } else {
634
+ const rightNode = bvh2Nodes[right];
635
+ out.children[slot] = rightNode.leftChild;
636
+ out.bounds[slot] = getChildBounds(
637
+ rightNode.leftChild,
638
+ bvh2Nodes,
639
+ triangles,
640
+ sortedPairs
641
+ );
642
+ slot++;
643
+ out.children[slot] = rightNode.rightChild;
644
+ out.bounds[slot] = getChildBounds(
645
+ rightNode.rightChild,
646
+ bvh2Nodes,
647
+ triangles,
648
+ sortedPairs
649
+ );
574
650
  }
575
651
  }
652
+
653
+ bvh4Nodes[i] = out;
576
654
  }
577
655
 
578
- return { valid: errors.length === 0, errors };
656
+ return bvh4Nodes;
579
657
  }
580
658
 
581
- const MAX_SHAPES = 16;
582
- const TREE_NODE_SIZE = 32;
583
659
  const BLAS_TRIANGLE_SIZE = 64;
584
660
 
585
- export interface BLASMetaExtended {
661
+ function createRefitBuffers(
662
+ device: GPUDevice,
663
+ blasData: Map<number, BLASData>,
664
+ trianglesMap: Map<number, BLASTriangle[]>,
665
+ metas: BLASMeta[],
666
+ totalTreeNodes: number,
667
+ totalParentIndices: number
668
+ ): { treeNodesBuffer: GPUBuffer; parentIndicesBuffer: GPUBuffer; boundsFlagsBuffer: GPUBuffer } {
669
+ const treeNodesData = new Uint32Array(Math.max(totalTreeNodes * 8, 8));
670
+ const treeNodesFloat = new Float32Array(treeNodesData.buffer);
671
+ const parentIndicesData = new Uint32Array(Math.max(totalParentIndices, 1));
672
+
673
+ let treeNodeWriteOffset = 0;
674
+ let parentWriteOffset = 0;
675
+
676
+ for (let shapeId = 0; shapeId < metas.length; shapeId++) {
677
+ const meta = metas[shapeId];
678
+ if (meta.triCount === 0) continue;
679
+ const blas = blasData.get(shapeId);
680
+ const triangles = trianglesMap.get(shapeId);
681
+ if (!blas || !triangles) continue;
682
+
683
+ const n = blas.triCount;
684
+ if (n <= 1) {
685
+ treeNodesData.fill(0, treeNodeWriteOffset * 8, treeNodeWriteOffset * 8 + 8);
686
+ treeNodeWriteOffset++;
687
+ parentIndicesData[parentWriteOffset++] = 0;
688
+ } else {
689
+ for (let i = 0; i < n - 1; i++) {
690
+ const bvhNode = blas.nodes[i];
691
+ const base = (treeNodeWriteOffset + i) * 8;
692
+ treeNodesFloat[base + 0] = bvhNode.min.x;
693
+ treeNodesFloat[base + 1] = bvhNode.min.y;
694
+ treeNodesFloat[base + 2] = bvhNode.min.z;
695
+ treeNodesData[base + 3] = bvhNode.leftChild >>> 0;
696
+ treeNodesFloat[base + 4] = bvhNode.max.x;
697
+ treeNodesFloat[base + 5] = bvhNode.max.y;
698
+ treeNodesFloat[base + 6] = bvhNode.max.z;
699
+ treeNodesData[base + 7] = bvhNode.rightChild >>> 0;
700
+ }
701
+
702
+ for (let leafIdx = 0; leafIdx < n; leafIdx++) {
703
+ const leafNodeIdx = n - 1 + leafIdx;
704
+ const base = (treeNodeWriteOffset + leafNodeIdx) * 8;
705
+ const triId = blas.sortedPairs[leafIdx].triangleId;
706
+ const tri = triangles[triId];
707
+ const v0 = tri.v0;
708
+ const v1 = vec3Add(v0, tri.e1);
709
+ const v2 = vec3Add(v0, tri.e2);
710
+ const tMin = vec3Min(vec3Min(v0, v1), v2);
711
+ const tMax = vec3Max(vec3Max(v0, v1), v2);
712
+ treeNodesFloat[base + 0] = tMin.x;
713
+ treeNodesFloat[base + 1] = tMin.y;
714
+ treeNodesFloat[base + 2] = tMin.z;
715
+ treeNodesData[base + 3] = 0;
716
+ treeNodesFloat[base + 4] = tMax.x;
717
+ treeNodesFloat[base + 5] = tMax.y;
718
+ treeNodesFloat[base + 6] = tMax.z;
719
+ treeNodesData[base + 7] = 0;
720
+ }
721
+
722
+ for (let i = 0; i < 2 * n; i++) {
723
+ parentIndicesData[parentWriteOffset + i] = blas.parents[i] >>> 0;
724
+ }
725
+
726
+ treeNodeWriteOffset += 2 * n - 1;
727
+ parentWriteOffset += 2 * n;
728
+ }
729
+ }
730
+
731
+ const treeNodesBuffer = device.createBuffer({
732
+ label: "blas-tree-nodes",
733
+ size: Math.max(treeNodesData.byteLength, 32),
734
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
735
+ });
736
+ device.queue.writeBuffer(treeNodesBuffer, 0, treeNodesData);
737
+
738
+ const parentIndicesBuffer = device.createBuffer({
739
+ label: "blas-parent-indices",
740
+ size: Math.max(parentIndicesData.byteLength, 4),
741
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
742
+ });
743
+ device.queue.writeBuffer(parentIndicesBuffer, 0, parentIndicesData);
744
+
745
+ const boundsFlagsBuffer = device.createBuffer({
746
+ label: "blas-bounds-flags",
747
+ size: Math.max(totalTreeNodes * 4, 4),
748
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
749
+ });
750
+
751
+ return { treeNodesBuffer, parentIndicesBuffer, boundsFlagsBuffer };
752
+ }
753
+
754
+ export interface BLASMeta {
586
755
  nodeOffset: number;
587
756
  triIdOffset: number;
588
757
  triOffset: number;
589
758
  triCount: number;
759
+ treeNodeOffset: number;
760
+ parentOffset: number;
590
761
  }
591
762
 
592
763
  export function createBLASAtlas(
593
764
  device: GPUDevice,
594
765
  getMesh: (id: number) => MeshData | undefined
595
766
  ): BLASAtlas {
767
+ const shapeCount = meshCount();
596
768
  const blasData = new Map<number, BLASData>();
769
+ const bvh4Data = new Map<number, BVH4Node[]>();
597
770
  const trianglesMap = new Map<number, BLASTriangle[]>();
598
- const metas: BLASMetaExtended[] = [];
771
+ const metas: BLASMeta[] = [];
599
772
 
600
773
  let totalNodes = 0;
601
774
  let totalTriIds = 0;
602
775
  let totalTris = 0;
776
+ let totalTreeNodes = 0;
777
+ let totalParentIndices = 0;
603
778
 
604
- for (let shapeId = 0; shapeId < MAX_SHAPES; shapeId++) {
779
+ for (let shapeId = 0; shapeId < shapeCount; shapeId++) {
605
780
  const mesh = getMesh(shapeId);
606
781
  if (!mesh || mesh.indexCount === 0) {
607
- metas.push({ nodeOffset: 0, triIdOffset: 0, triOffset: 0, triCount: 0 });
782
+ metas.push({
783
+ nodeOffset: 0,
784
+ triIdOffset: 0,
785
+ triOffset: 0,
786
+ triCount: 0,
787
+ treeNodeOffset: 0,
788
+ parentOffset: 0,
789
+ });
608
790
  continue;
609
791
  }
610
792
 
@@ -613,45 +795,89 @@ export function createBLASAtlas(
613
795
  blasData.set(shapeId, blas);
614
796
  trianglesMap.set(shapeId, triangles);
615
797
 
798
+ const bvh4Nodes = collapseToBVH4(
799
+ blas.nodes,
800
+ blas.triCount,
801
+ blas.sortedPairs,
802
+ triangles,
803
+ blas.parents
804
+ );
805
+ bvh4Data.set(shapeId, bvh4Nodes);
806
+
807
+ const n = blas.triCount;
808
+ const treeNodeCount = n <= 1 ? 1 : 2 * n - 1;
809
+ const parentCount = n <= 1 ? 1 : 2 * n;
810
+
616
811
  metas.push({
617
812
  nodeOffset: totalNodes,
618
813
  triIdOffset: totalTriIds,
619
814
  triOffset: totalTris,
620
815
  triCount: blas.triCount,
816
+ treeNodeOffset: totalTreeNodes,
817
+ parentOffset: totalParentIndices,
621
818
  });
622
819
 
623
- totalNodes += blas.nodes.length;
820
+ totalNodes += bvh4Nodes.length;
624
821
  totalTriIds += blas.sortedTriIds.length;
625
822
  totalTris += triangles.length;
823
+ totalTreeNodes += treeNodeCount;
824
+ totalParentIndices += parentCount;
626
825
  }
627
826
 
628
- const nodesData = new Float32Array(Math.max(totalNodes * 8, 8));
827
+ const nodesData = new Float32Array(Math.max(totalNodes * 32, 32));
828
+ const nodesU32 = new Uint32Array(nodesData.buffer);
629
829
  const triIdsData = new Uint32Array(Math.max(totalTriIds, 1));
630
- const metaData = new Uint32Array(MAX_SHAPES * 4);
830
+ const metaData = new Uint32Array(shapeCount * 4);
631
831
  const trianglesData = new Uint32Array(Math.max(totalTris * 16, 16));
632
832
 
633
833
  let nodeOffset = 0;
634
834
  let triIdOffset = 0;
635
835
  let triOffset = 0;
636
836
 
637
- for (let shapeId = 0; shapeId < MAX_SHAPES; shapeId++) {
837
+ for (let shapeId = 0; shapeId < shapeCount; shapeId++) {
638
838
  const blas = blasData.get(shapeId);
839
+ const bvh4Nodes = bvh4Data.get(shapeId);
639
840
  const triangles = trianglesMap.get(shapeId);
640
- if (!blas || !triangles) continue;
841
+ if (!blas || !triangles || !bvh4Nodes) continue;
842
+
843
+ for (const node of bvh4Nodes) {
844
+ const base = nodeOffset * 32;
845
+ nodesData[base + 0] = node.bounds[0].min.x;
846
+ nodesData[base + 1] = node.bounds[0].min.y;
847
+ nodesData[base + 2] = node.bounds[0].min.z;
848
+ nodesU32[base + 3] = node.children[0];
849
+ nodesData[base + 4] = node.bounds[0].max.x;
850
+ nodesData[base + 5] = node.bounds[0].max.y;
851
+ nodesData[base + 6] = node.bounds[0].max.z;
852
+ nodesData[base + 7] = 0;
853
+
854
+ nodesData[base + 8] = node.bounds[1].min.x;
855
+ nodesData[base + 9] = node.bounds[1].min.y;
856
+ nodesData[base + 10] = node.bounds[1].min.z;
857
+ nodesU32[base + 11] = node.children[1];
858
+ nodesData[base + 12] = node.bounds[1].max.x;
859
+ nodesData[base + 13] = node.bounds[1].max.y;
860
+ nodesData[base + 14] = node.bounds[1].max.z;
861
+ nodesData[base + 15] = 0;
862
+
863
+ nodesData[base + 16] = node.bounds[2].min.x;
864
+ nodesData[base + 17] = node.bounds[2].min.y;
865
+ nodesData[base + 18] = node.bounds[2].min.z;
866
+ nodesU32[base + 19] = node.children[2];
867
+ nodesData[base + 20] = node.bounds[2].max.x;
868
+ nodesData[base + 21] = node.bounds[2].max.y;
869
+ nodesData[base + 22] = node.bounds[2].max.z;
870
+ nodesData[base + 23] = 0;
871
+
872
+ nodesData[base + 24] = node.bounds[3].min.x;
873
+ nodesData[base + 25] = node.bounds[3].min.y;
874
+ nodesData[base + 26] = node.bounds[3].min.z;
875
+ nodesU32[base + 27] = node.children[3];
876
+ nodesData[base + 28] = node.bounds[3].max.x;
877
+ nodesData[base + 29] = node.bounds[3].max.y;
878
+ nodesData[base + 30] = node.bounds[3].max.z;
879
+ nodesData[base + 31] = 0;
641
880
 
642
- for (const node of blas.nodes) {
643
- nodesData[nodeOffset * 8 + 0] = node.min.x;
644
- nodesData[nodeOffset * 8 + 1] = node.min.y;
645
- nodesData[nodeOffset * 8 + 2] = node.min.z;
646
- nodesData[nodeOffset * 8 + 3] = new Float32Array(
647
- new Uint32Array([node.leftChild]).buffer
648
- )[0];
649
- nodesData[nodeOffset * 8 + 4] = node.max.x;
650
- nodesData[nodeOffset * 8 + 5] = node.max.y;
651
- nodesData[nodeOffset * 8 + 6] = node.max.z;
652
- nodesData[nodeOffset * 8 + 7] = new Float32Array(
653
- new Uint32Array([node.rightChild]).buffer
654
- )[0];
655
881
  nodeOffset++;
656
882
  }
657
883
 
@@ -678,6 +904,7 @@ export function createBLASAtlas(
678
904
  trianglesData[base + 13] = octEncode(tri.n1);
679
905
  trianglesData[base + 14] = octEncode(tri.n2);
680
906
  trianglesData[base + 15] = 0;
907
+
681
908
  triOffset++;
682
909
  }
683
910
  }
@@ -691,7 +918,7 @@ export function createBLASAtlas(
691
918
 
692
919
  const nodesBuffer = device.createBuffer({
693
920
  label: "blas-nodes",
694
- size: Math.max(nodesData.byteLength, 32),
921
+ size: Math.max(nodesData.byteLength, 128),
695
922
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
696
923
  });
697
924
  device.queue.writeBuffer(nodesBuffer, 0, nodesData);
@@ -717,8 +944,24 @@ export function createBLASAtlas(
717
944
  });
718
945
  device.queue.writeBuffer(trianglesBuffer, 0, trianglesData);
719
946
 
720
- const shapeAABBsData = new Float32Array(MAX_SHAPES * 8);
721
- for (let shapeId = 0; shapeId < MAX_SHAPES; shapeId++) {
947
+ const baseTrianglesBuffer = device.createBuffer({
948
+ label: "blas-base-triangles",
949
+ size: Math.max(totalTris * BLAS_TRIANGLE_SIZE, BLAS_TRIANGLE_SIZE),
950
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
951
+ });
952
+ device.queue.writeBuffer(baseTrianglesBuffer, 0, trianglesData);
953
+
954
+ const { treeNodesBuffer, parentIndicesBuffer, boundsFlagsBuffer } = createRefitBuffers(
955
+ device,
956
+ blasData,
957
+ trianglesMap,
958
+ metas,
959
+ totalTreeNodes,
960
+ totalParentIndices
961
+ );
962
+
963
+ const shapeAABBsData = new Float32Array(shapeCount * 8);
964
+ for (let shapeId = 0; shapeId < shapeCount; shapeId++) {
722
965
  const blas = blasData.get(shapeId);
723
966
  const offset = shapeId * 8;
724
967
  if (blas) {
@@ -748,5 +991,10 @@ export function createBLASAtlas(
748
991
  trianglesBuffer,
749
992
  triangles: trianglesMap,
750
993
  shapeAABBs,
994
+ treeNodesBuffer,
995
+ parentIndicesBuffer,
996
+ baseTrianglesBuffer,
997
+ boundsFlagsBuffer,
998
+ metas,
751
999
  };
752
1000
  }