@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.
- package/package.json +1 -1
- package/src/core/component.ts +1 -1
- package/src/core/index.ts +1 -13
- package/src/core/math.ts +186 -0
- package/src/core/state.ts +1 -1
- package/src/core/xml.ts +56 -41
- package/src/extras/orbit/index.ts +1 -1
- package/src/extras/text/index.ts +10 -65
- package/src/extras/{water.ts → water/index.ts} +59 -4
- package/src/standard/raster/batch.ts +149 -0
- package/src/standard/raster/forward.ts +832 -0
- package/src/standard/raster/index.ts +146 -472
- package/src/standard/raster/shadow.ts +408 -0
- package/src/standard/raytracing/bvh/blas.ts +335 -87
- package/src/standard/raytracing/bvh/radix.ts +225 -228
- package/src/standard/raytracing/bvh/refit.ts +711 -0
- package/src/standard/raytracing/bvh/structs.ts +0 -55
- package/src/standard/raytracing/bvh/tlas.ts +153 -141
- package/src/standard/raytracing/bvh/traverse.ts +72 -64
- package/src/standard/raytracing/index.ts +233 -204
- package/src/standard/raytracing/instance.ts +30 -18
- package/src/standard/raytracing/ray.ts +1 -1
- package/src/standard/raytracing/shaders.ts +23 -40
- package/src/standard/render/camera.ts +10 -28
- package/src/standard/render/data.ts +1 -1
- package/src/standard/render/index.ts +68 -12
- package/src/standard/render/light.ts +2 -2
- package/src/standard/render/mesh.ts +404 -0
- package/src/standard/render/overlay.ts +5 -2
- package/src/standard/render/postprocess.ts +263 -267
- package/src/standard/render/surface/index.ts +81 -12
- package/src/standard/render/surface/shaders.ts +265 -11
- package/src/standard/render/surface/structs.ts +10 -0
- package/src/standard/tween/tween.ts +44 -115
- package/src/standard/render/mesh/box.ts +0 -20
- package/src/standard/render/mesh/index.ts +0 -315
- package/src/standard/render/mesh/plane.ts +0 -11
- package/src/standard/render/mesh/sphere.ts +0 -40
- package/src/standard/render/mesh/unified.ts +0 -96
- package/src/standard/render/surface/compile.ts +0 -65
- 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
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
511
|
+
export interface BVH4Node {
|
|
512
|
+
children: [number, number, number, number];
|
|
513
|
+
bounds: [AABB, AABB, AABB, AABB];
|
|
514
|
+
}
|
|
510
515
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
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
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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
|
|
534
|
-
|
|
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
|
-
|
|
537
|
-
|
|
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
|
-
|
|
541
|
-
|
|
542
|
-
|
|
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
|
-
|
|
546
|
-
const
|
|
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
|
-
|
|
549
|
-
|
|
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
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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
|
-
|
|
562
|
-
errors.push(`Node ${i} left child ${left} >= node count ${blas.nodes.length}`);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
604
|
+
let slot = 0;
|
|
565
605
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
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
|
-
|
|
572
|
-
if (right
|
|
573
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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 <
|
|
779
|
+
for (let shapeId = 0; shapeId < shapeCount; shapeId++) {
|
|
605
780
|
const mesh = getMesh(shapeId);
|
|
606
781
|
if (!mesh || mesh.indexCount === 0) {
|
|
607
|
-
metas.push({
|
|
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 +=
|
|
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 *
|
|
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(
|
|
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 <
|
|
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,
|
|
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
|
|
721
|
-
|
|
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
|
}
|