@plasius/gpu-renderer 0.1.15 → 0.2.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/CHANGELOG.md +5 -3
- package/README.md +8 -0
- package/dist/index.cjs +251 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +248 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.d.ts +78 -0
- package/src/index.js +3 -0
- package/src/wavefront-compute.js +280 -0
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -162,6 +162,69 @@ export interface WavefrontMeshAcceleration {
|
|
|
162
162
|
readonly triangles: readonly WavefrontTriangleRecord[];
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
export interface WavefrontReferenceRay {
|
|
166
|
+
readonly rayId: number;
|
|
167
|
+
readonly parentRayId: number;
|
|
168
|
+
readonly sourcePixelId: number;
|
|
169
|
+
readonly sampleId: number;
|
|
170
|
+
readonly bounce: number;
|
|
171
|
+
readonly mediumRefId: number;
|
|
172
|
+
readonly flags: number;
|
|
173
|
+
readonly origin: readonly [number, number, number] | readonly number[];
|
|
174
|
+
readonly direction: readonly [number, number, number] | readonly number[];
|
|
175
|
+
readonly throughput: readonly [number, number, number, number] | readonly number[];
|
|
176
|
+
readonly pixelX: number;
|
|
177
|
+
readonly pixelY: number;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface WavefrontReferenceTile {
|
|
181
|
+
readonly x?: number;
|
|
182
|
+
readonly y?: number;
|
|
183
|
+
readonly width?: number;
|
|
184
|
+
readonly height?: number;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface CreateWavefrontReferenceRayOptions {
|
|
188
|
+
readonly tile?: WavefrontReferenceTile;
|
|
189
|
+
readonly pixelIndex?: number;
|
|
190
|
+
readonly sampleIndex?: number;
|
|
191
|
+
readonly frameIndex?: number;
|
|
192
|
+
readonly jitterScale?: number;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export interface WavefrontReferenceHit {
|
|
196
|
+
readonly hitType: "surface" | "environment";
|
|
197
|
+
readonly rayId: number;
|
|
198
|
+
readonly sourcePixelId: number;
|
|
199
|
+
readonly distance: number;
|
|
200
|
+
readonly entityId: number;
|
|
201
|
+
readonly instanceId: number;
|
|
202
|
+
readonly primitiveId: number;
|
|
203
|
+
readonly materialId: number;
|
|
204
|
+
readonly materialRefId: number;
|
|
205
|
+
readonly mediumRefId: number;
|
|
206
|
+
readonly barycentrics: readonly [number, number, number] | readonly number[];
|
|
207
|
+
readonly uv: readonly [number, number] | readonly number[];
|
|
208
|
+
readonly geometricNormal: readonly [number, number, number] | readonly number[];
|
|
209
|
+
readonly shadingNormal: readonly [number, number, number] | readonly number[];
|
|
210
|
+
readonly frontFace: boolean;
|
|
211
|
+
readonly triangleIndex: number;
|
|
212
|
+
readonly triangleId: number;
|
|
213
|
+
readonly position: readonly [number, number, number] | readonly number[];
|
|
214
|
+
readonly color: readonly number[];
|
|
215
|
+
readonly emission: readonly number[];
|
|
216
|
+
readonly material: readonly number[];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface IntersectWavefrontReferenceTriangleOptions {
|
|
220
|
+
readonly maxDistance?: number;
|
|
221
|
+
readonly triangleIndex?: number;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface TraceWavefrontReferenceTrianglesOptions {
|
|
225
|
+
readonly maxDistance?: number;
|
|
226
|
+
}
|
|
227
|
+
|
|
165
228
|
export type WavefrontAccelerationBuildMode = "gpu" | "cpu-debug";
|
|
166
229
|
|
|
167
230
|
export interface WavefrontGpuMeshSource {
|
|
@@ -490,6 +553,21 @@ export function createWavefrontBvhSortStages(
|
|
|
490
553
|
export function createWavefrontPathTracingComputeConfig(
|
|
491
554
|
options?: CreateWavefrontPathTracingComputeRendererOptions
|
|
492
555
|
): WavefrontPathTracingComputeConfig;
|
|
556
|
+
export function createWavefrontReferenceRay(
|
|
557
|
+
config: WavefrontPathTracingComputeConfig,
|
|
558
|
+
options?: CreateWavefrontReferenceRayOptions
|
|
559
|
+
): WavefrontReferenceRay;
|
|
560
|
+
export function intersectWavefrontReferenceTriangle(
|
|
561
|
+
ray: WavefrontReferenceRay,
|
|
562
|
+
triangle: WavefrontTriangleRecord,
|
|
563
|
+
options?: IntersectWavefrontReferenceTriangleOptions
|
|
564
|
+
): WavefrontReferenceHit | null;
|
|
565
|
+
export function traceWavefrontReferenceTriangles(
|
|
566
|
+
config: WavefrontPathTracingComputeConfig,
|
|
567
|
+
ray: WavefrontReferenceRay,
|
|
568
|
+
triangles: readonly WavefrontTriangleRecord[],
|
|
569
|
+
options?: TraceWavefrontReferenceTrianglesOptions
|
|
570
|
+
): WavefrontReferenceHit;
|
|
493
571
|
export function packWavefrontSceneObjects(
|
|
494
572
|
sceneObjects: readonly WavefrontSceneObjectInput[],
|
|
495
573
|
capacity?: number
|
package/src/index.js
CHANGED
|
@@ -9,13 +9,16 @@ export {
|
|
|
9
9
|
createWavefrontMeshAcceleration,
|
|
10
10
|
createWavefrontPathTracingComputeConfig,
|
|
11
11
|
createWavefrontPathTracingComputeRenderer,
|
|
12
|
+
createWavefrontReferenceRay,
|
|
12
13
|
estimateWavefrontPathTracingMemory,
|
|
14
|
+
intersectWavefrontReferenceTriangle,
|
|
13
15
|
normalizeWavefrontMesh,
|
|
14
16
|
normalizeWavefrontSceneObject,
|
|
15
17
|
packWavefrontBvhNodes,
|
|
16
18
|
packWavefrontSceneObjects,
|
|
17
19
|
packWavefrontTriangles,
|
|
18
20
|
supportsWavefrontPathTracingCompute,
|
|
21
|
+
traceWavefrontReferenceTriangles,
|
|
19
22
|
wavefrontMaterialKinds,
|
|
20
23
|
wavefrontPathTracingComputeLimits,
|
|
21
24
|
wavefrontSceneObjectKinds,
|
package/src/wavefront-compute.js
CHANGED
|
@@ -194,6 +194,33 @@ function normalize(value, fallback = [0, 0, 1]) {
|
|
|
194
194
|
return [value[0] / length, value[1] / length, value[2] / length];
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
function hashUint32(value) {
|
|
198
|
+
let x = value >>> 0;
|
|
199
|
+
x = ((((x >>> 16) ^ x) >>> 0) * 0x45d9f3b) >>> 0;
|
|
200
|
+
x = ((((x >>> 16) ^ x) >>> 0) * 0x45d9f3b) >>> 0;
|
|
201
|
+
return ((x >>> 16) ^ x) >>> 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function mixSeed(pixelId, sampleId, bounce, frameIndex, dimension) {
|
|
205
|
+
let x =
|
|
206
|
+
((pixelId >>> 0) * 747796405) ^
|
|
207
|
+
((sampleId >>> 0) * 2891336453) ^
|
|
208
|
+
((bounce >>> 0) * 277803737) ^
|
|
209
|
+
((frameIndex >>> 0) * 1442695041) ^
|
|
210
|
+
((dimension >>> 0) * 1597334677);
|
|
211
|
+
x >>>= 0;
|
|
212
|
+
x ^= x >>> 16;
|
|
213
|
+
x = (x * 0x7feb352d) >>> 0;
|
|
214
|
+
x ^= x >>> 15;
|
|
215
|
+
x = (x * 0x846ca68b) >>> 0;
|
|
216
|
+
x ^= x >>> 16;
|
|
217
|
+
return x >>> 0;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function random01FromSeed(seed) {
|
|
221
|
+
return (hashUint32(seed) & 0x00ffffff) / 16777215;
|
|
222
|
+
}
|
|
223
|
+
|
|
197
224
|
function getArrayLikeLength(value) {
|
|
198
225
|
return Array.isArray(value) || ArrayBuffer.isView(value) ? value.length : 0;
|
|
199
226
|
}
|
|
@@ -882,6 +909,36 @@ function resolveEnvironmentLighting(input, environmentColor, ambientColor) {
|
|
|
882
909
|
});
|
|
883
910
|
}
|
|
884
911
|
|
|
912
|
+
function evaluateReferenceEnvironmentRadiance(config, origin, direction) {
|
|
913
|
+
void origin;
|
|
914
|
+
const rayDirection = normalize(direction, [0, 1, 0]);
|
|
915
|
+
const upFactor = clamp(rayDirection[1] * 0.5 + 0.5, 0, 1);
|
|
916
|
+
const sunDirection = normalize(
|
|
917
|
+
config.environmentLighting?.sunDirection ?? DEFAULT_ENVIRONMENT_LIGHTING.sunDirection,
|
|
918
|
+
DEFAULT_ENVIRONMENT_LIGHTING.sunDirection
|
|
919
|
+
);
|
|
920
|
+
const sunGlow = Math.pow(clamp(dot(rayDirection, sunDirection), 0, 1), 192);
|
|
921
|
+
const horizonColor =
|
|
922
|
+
config.environmentLighting?.horizonColor ?? DEFAULT_ENVIRONMENT_LIGHTING.horizonColor;
|
|
923
|
+
const zenithColor =
|
|
924
|
+
config.environmentLighting?.zenithColor ?? DEFAULT_ENVIRONMENT_LIGHTING.zenithColor;
|
|
925
|
+
const sunColor = config.environmentLighting?.sunColor ?? DEFAULT_ENVIRONMENT_LIGHTING.sunColor;
|
|
926
|
+
const intensity = Math.max(
|
|
927
|
+
0.0001,
|
|
928
|
+
Number(config.environmentLighting?.intensity ?? DEFAULT_ENVIRONMENT_LIGHTING.intensity)
|
|
929
|
+
);
|
|
930
|
+
|
|
931
|
+
return Object.freeze([
|
|
932
|
+
(horizonColor[0] * (1 - upFactor) + zenithColor[0] * upFactor + sunColor[0] * sunGlow) *
|
|
933
|
+
intensity,
|
|
934
|
+
(horizonColor[1] * (1 - upFactor) + zenithColor[1] * upFactor + sunColor[1] * sunGlow) *
|
|
935
|
+
intensity,
|
|
936
|
+
(horizonColor[2] * (1 - upFactor) + zenithColor[2] * upFactor + sunColor[2] * sunGlow) *
|
|
937
|
+
intensity,
|
|
938
|
+
1,
|
|
939
|
+
]);
|
|
940
|
+
}
|
|
941
|
+
|
|
885
942
|
function resolveEnvironmentPortalMode(value, hasPortals) {
|
|
886
943
|
if (value === undefined || value === null) {
|
|
887
944
|
return hasPortals ? 2 : 0;
|
|
@@ -1489,6 +1546,229 @@ function createTiles(width, height, tileSize) {
|
|
|
1489
1546
|
return Object.freeze(tiles);
|
|
1490
1547
|
}
|
|
1491
1548
|
|
|
1549
|
+
function normalizeReferenceTile(config, tileInput = {}) {
|
|
1550
|
+
const tileX = clamp(
|
|
1551
|
+
readNonNegativeInteger("tile.x", tileInput.x, 0),
|
|
1552
|
+
0,
|
|
1553
|
+
Math.max(0, config.width - 1)
|
|
1554
|
+
);
|
|
1555
|
+
const tileY = clamp(
|
|
1556
|
+
readNonNegativeInteger("tile.y", tileInput.y, 0),
|
|
1557
|
+
0,
|
|
1558
|
+
Math.max(0, config.height - 1)
|
|
1559
|
+
);
|
|
1560
|
+
const tileWidth = clamp(
|
|
1561
|
+
readPositiveInteger("tile.width", tileInput.width, config.width - tileX),
|
|
1562
|
+
1,
|
|
1563
|
+
config.width - tileX
|
|
1564
|
+
);
|
|
1565
|
+
const tileHeight = clamp(
|
|
1566
|
+
readPositiveInteger("tile.height", tileInput.height, config.height - tileY),
|
|
1567
|
+
1,
|
|
1568
|
+
config.height - tileY
|
|
1569
|
+
);
|
|
1570
|
+
|
|
1571
|
+
return Object.freeze({
|
|
1572
|
+
x: tileX,
|
|
1573
|
+
y: tileY,
|
|
1574
|
+
width: tileWidth,
|
|
1575
|
+
height: tileHeight,
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
function repairReferenceShadingNormal(geometricNormal, shadingNormal) {
|
|
1580
|
+
const normal = normalize(shadingNormal, geometricNormal);
|
|
1581
|
+
return dot(normal, geometricNormal) < 0 ? scale(normal, -1) : normal;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
function readOptionalMaxDistance(value) {
|
|
1585
|
+
if (value === undefined || value === null) {
|
|
1586
|
+
return Number.POSITIVE_INFINITY;
|
|
1587
|
+
}
|
|
1588
|
+
const numeric = Number(value);
|
|
1589
|
+
if (!Number.isFinite(numeric) || numeric <= 0) {
|
|
1590
|
+
throw new Error("maxDistance must be a positive finite number when provided.");
|
|
1591
|
+
}
|
|
1592
|
+
return numeric;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
export function createWavefrontReferenceRay(config, options = {}) {
|
|
1596
|
+
if (!config || typeof config !== "object") {
|
|
1597
|
+
throw new Error("config must be a wavefront path tracing config.");
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
const tile = normalizeReferenceTile(config, options.tile);
|
|
1601
|
+
const tilePixelCount = tile.width * tile.height;
|
|
1602
|
+
const pixelIndex = readNonNegativeInteger("pixelIndex", options.pixelIndex, 0);
|
|
1603
|
+
if (pixelIndex >= tilePixelCount) {
|
|
1604
|
+
throw new Error(`pixelIndex ${pixelIndex} exceeds tile capacity ${tilePixelCount}.`);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
const sampleIndex = readNonNegativeInteger("sampleIndex", options.sampleIndex, 0);
|
|
1608
|
+
const frameIndex = readNonNegativeInteger("frameIndex", options.frameIndex, config.frameIndex ?? 0);
|
|
1609
|
+
const jitterScale = clamp(readFiniteNumber("jitterScale", options.jitterScale, 0.35), 0, 1);
|
|
1610
|
+
const localX = pixelIndex % tile.width;
|
|
1611
|
+
const localY = Math.floor(pixelIndex / tile.width);
|
|
1612
|
+
const pixelX = tile.x + localX;
|
|
1613
|
+
const pixelY = tile.y + localY;
|
|
1614
|
+
const sourcePixelId = pixelY * config.width + pixelX;
|
|
1615
|
+
const jitterX = random01FromSeed(mixSeed(sourcePixelId, sampleIndex, 0, frameIndex, 1)) - 0.5;
|
|
1616
|
+
const jitterY = random01FromSeed(mixSeed(sourcePixelId, sampleIndex, 0, frameIndex, 2)) - 0.5;
|
|
1617
|
+
const ndcX = ((pixelX + 0.5 + jitterX * jitterScale) / config.width) * 2 - 1;
|
|
1618
|
+
const ndcY = 1 - ((pixelY + 0.5 + jitterY * jitterScale) / config.height) * 2;
|
|
1619
|
+
const viewX = ndcX * config.camera.tanHalfFovY * config.camera.aspect;
|
|
1620
|
+
const viewY = ndcY * config.camera.tanHalfFovY;
|
|
1621
|
+
const direction = normalize(
|
|
1622
|
+
add(
|
|
1623
|
+
add(config.camera.forward, scale(config.camera.right, viewX)),
|
|
1624
|
+
scale(config.camera.up, viewY)
|
|
1625
|
+
),
|
|
1626
|
+
config.camera.forward
|
|
1627
|
+
);
|
|
1628
|
+
|
|
1629
|
+
return Object.freeze({
|
|
1630
|
+
rayId: pixelIndex,
|
|
1631
|
+
parentRayId: 0xffffffff,
|
|
1632
|
+
sourcePixelId,
|
|
1633
|
+
sampleId: sampleIndex,
|
|
1634
|
+
bounce: 0,
|
|
1635
|
+
mediumRefId: 0,
|
|
1636
|
+
flags: 0,
|
|
1637
|
+
origin: Object.freeze([...config.camera.position]),
|
|
1638
|
+
direction: Object.freeze(direction),
|
|
1639
|
+
throughput: Object.freeze([1, 1, 1, 1]),
|
|
1640
|
+
pixelX,
|
|
1641
|
+
pixelY,
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
export function intersectWavefrontReferenceTriangle(ray, triangle, options = {}) {
|
|
1646
|
+
if (!ray || typeof ray !== "object") {
|
|
1647
|
+
throw new Error("ray must be a wavefront reference ray.");
|
|
1648
|
+
}
|
|
1649
|
+
if (!triangle || typeof triangle !== "object") {
|
|
1650
|
+
throw new Error("triangle must be a wavefront triangle record.");
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
const maxDistance = readOptionalMaxDistance(options.maxDistance);
|
|
1654
|
+
const triangleIndex = readNonNegativeInteger("triangleIndex", options.triangleIndex, 0);
|
|
1655
|
+
const edge1 = subtract(triangle.v1, triangle.v0);
|
|
1656
|
+
const edge2 = subtract(triangle.v2, triangle.v0);
|
|
1657
|
+
const pvec = cross(ray.direction, edge2);
|
|
1658
|
+
const determinant = dot(edge1, pvec);
|
|
1659
|
+
if (Math.abs(determinant) < 0.0000001) {
|
|
1660
|
+
return null;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
const invDet = 1 / determinant;
|
|
1664
|
+
const tvec = subtract(ray.origin, triangle.v0);
|
|
1665
|
+
const u = dot(tvec, pvec) * invDet;
|
|
1666
|
+
if (u < 0 || u > 1) {
|
|
1667
|
+
return null;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
const qvec = cross(tvec, edge1);
|
|
1671
|
+
const v = dot(ray.direction, qvec) * invDet;
|
|
1672
|
+
if (v < 0 || u + v > 1) {
|
|
1673
|
+
return null;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
const distance = dot(edge2, qvec) * invDet;
|
|
1677
|
+
if (distance <= 0.001 || distance > maxDistance) {
|
|
1678
|
+
return null;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
const geometric = normalize(cross(edge1, edge2), [0, 1, 0]);
|
|
1682
|
+
const frontFace = dot(ray.direction, geometric) < 0;
|
|
1683
|
+
const orientedGeometric = frontFace ? geometric : scale(geometric, -1);
|
|
1684
|
+
const w = 1 - u - v;
|
|
1685
|
+
const interpolated = [
|
|
1686
|
+
triangle.n0[0] * w + triangle.n1[0] * u + triangle.n2[0] * v,
|
|
1687
|
+
triangle.n0[1] * w + triangle.n1[1] * u + triangle.n2[1] * v,
|
|
1688
|
+
triangle.n0[2] * w + triangle.n1[2] * u + triangle.n2[2] * v,
|
|
1689
|
+
];
|
|
1690
|
+
const shadingNormal = repairReferenceShadingNormal(orientedGeometric, interpolated);
|
|
1691
|
+
const uv = [
|
|
1692
|
+
triangle.uv0[0] * w + triangle.uv1[0] * u + triangle.uv2[0] * v,
|
|
1693
|
+
triangle.uv0[1] * w + triangle.uv1[1] * u + triangle.uv2[1] * v,
|
|
1694
|
+
];
|
|
1695
|
+
const position = add(ray.origin, scale(ray.direction, distance));
|
|
1696
|
+
|
|
1697
|
+
return Object.freeze({
|
|
1698
|
+
hitType: "surface",
|
|
1699
|
+
rayId: ray.rayId,
|
|
1700
|
+
sourcePixelId: ray.sourcePixelId,
|
|
1701
|
+
distance,
|
|
1702
|
+
entityId: triangle.meshId,
|
|
1703
|
+
instanceId: 0,
|
|
1704
|
+
primitiveId: triangle.triangleId,
|
|
1705
|
+
materialId: triangle.materialKind,
|
|
1706
|
+
materialRefId: triangle.materialRefId,
|
|
1707
|
+
mediumRefId: triangle.mediumRefId,
|
|
1708
|
+
barycentrics: Object.freeze([w, u, v]),
|
|
1709
|
+
uv: Object.freeze(uv),
|
|
1710
|
+
geometricNormal: Object.freeze(orientedGeometric),
|
|
1711
|
+
shadingNormal: Object.freeze(shadingNormal),
|
|
1712
|
+
frontFace,
|
|
1713
|
+
triangleIndex,
|
|
1714
|
+
triangleId: triangle.triangleId,
|
|
1715
|
+
position: Object.freeze(position),
|
|
1716
|
+
color: triangle.color,
|
|
1717
|
+
emission: triangle.emission,
|
|
1718
|
+
material: triangle.material,
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
function createWavefrontReferenceEnvironmentHit(config, ray) {
|
|
1723
|
+
const radiance = evaluateReferenceEnvironmentRadiance(config, ray.origin, ray.direction);
|
|
1724
|
+
return Object.freeze({
|
|
1725
|
+
hitType: "environment",
|
|
1726
|
+
rayId: ray.rayId,
|
|
1727
|
+
sourcePixelId: ray.sourcePixelId,
|
|
1728
|
+
distance: -1,
|
|
1729
|
+
entityId: 0,
|
|
1730
|
+
instanceId: 0,
|
|
1731
|
+
primitiveId: 0,
|
|
1732
|
+
materialId: 0,
|
|
1733
|
+
materialRefId: 0,
|
|
1734
|
+
mediumRefId: 0,
|
|
1735
|
+
barycentrics: Object.freeze([0, 0, 0]),
|
|
1736
|
+
uv: Object.freeze([0, 0]),
|
|
1737
|
+
geometricNormal: Object.freeze(scale(ray.direction, -1)),
|
|
1738
|
+
shadingNormal: Object.freeze(scale(ray.direction, -1)),
|
|
1739
|
+
frontFace: true,
|
|
1740
|
+
triangleIndex: -1,
|
|
1741
|
+
triangleId: -1,
|
|
1742
|
+
position: Object.freeze(add(ray.origin, scale(ray.direction, 1000))),
|
|
1743
|
+
color: Object.freeze([0, 0, 0, 0]),
|
|
1744
|
+
emission: radiance,
|
|
1745
|
+
material: Object.freeze([1, 0, 1, 1]),
|
|
1746
|
+
});
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
export function traceWavefrontReferenceTriangles(config, ray, triangles, options = {}) {
|
|
1750
|
+
if (!config || typeof config !== "object") {
|
|
1751
|
+
throw new Error("config must be a wavefront path tracing config.");
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
const source = Array.isArray(triangles) ? triangles : [];
|
|
1755
|
+
let nearestHit = null;
|
|
1756
|
+
let nearestDistance = readOptionalMaxDistance(options.maxDistance);
|
|
1757
|
+
|
|
1758
|
+
source.forEach((triangle, index) => {
|
|
1759
|
+
const hit = intersectWavefrontReferenceTriangle(ray, triangle, {
|
|
1760
|
+
maxDistance: Number.isFinite(nearestDistance) ? nearestDistance : undefined,
|
|
1761
|
+
triangleIndex: index,
|
|
1762
|
+
});
|
|
1763
|
+
if (hit && hit.distance < nearestDistance) {
|
|
1764
|
+
nearestDistance = hit.distance;
|
|
1765
|
+
nearestHit = hit;
|
|
1766
|
+
}
|
|
1767
|
+
});
|
|
1768
|
+
|
|
1769
|
+
return nearestHit ?? createWavefrontReferenceEnvironmentHit(config, ray);
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1492
1772
|
function clampTileSizeForDevice(config, device) {
|
|
1493
1773
|
const limit = Number(device?.limits?.maxStorageBufferBindingSize);
|
|
1494
1774
|
if (!Number.isFinite(limit) || limit <= 0) {
|