@plasius/gpu-lighting 0.2.6 → 0.2.8
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 +32 -1
- package/README.md +61 -0
- package/dist/index.cjs +333 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +325 -7
- package/dist/index.js.map +1 -1
- package/dist/techniques/techniques/wavefront/prelude.wgsl +8 -0
- package/package.json +1 -1
- package/src/index.js +361 -7
- package/src/techniques/wavefront/prelude.wgsl +8 -0
|
@@ -13,6 +13,10 @@ const EVENT_KIND_REFRACTION: u32 = 2u;
|
|
|
13
13
|
const EVENT_KIND_TRANSPARENCY: u32 = 3u;
|
|
14
14
|
const EVENT_KIND_TERMINATE: u32 = 4u;
|
|
15
15
|
|
|
16
|
+
const RAY_KIND_PATH: u32 = 0u;
|
|
17
|
+
const RAY_KIND_VISIBILITY_PROBE: u32 = 1u;
|
|
18
|
+
const RAY_KIND_MASK: u32 = 0x3u;
|
|
19
|
+
|
|
16
20
|
const LIGHTING_EPSILON: f32 = 0.0001;
|
|
17
21
|
const LIGHTING_INV_PI: f32 = 0.3183098861837907;
|
|
18
22
|
|
|
@@ -147,6 +151,10 @@ fn is_terminal_hit_type(hit_type: u32) -> bool {
|
|
|
147
151
|
hit_type == HIT_TYPE_MISS;
|
|
148
152
|
}
|
|
149
153
|
|
|
154
|
+
fn ray_kind(flags: u32) -> u32 {
|
|
155
|
+
return flags & RAY_KIND_MASK;
|
|
156
|
+
}
|
|
157
|
+
|
|
150
158
|
fn environment_radiance(direction: vec3<f32>) -> vec3<f32> {
|
|
151
159
|
let upward = saturate_scalar(direction.y * 0.5 + 0.5);
|
|
152
160
|
let directional = mix(
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1146,6 +1146,15 @@ export const lightingWavefrontHitTypes = Object.freeze([
|
|
|
1146
1146
|
"transparent",
|
|
1147
1147
|
"miss",
|
|
1148
1148
|
]);
|
|
1149
|
+
export const lightingWavefrontRayKinds = Object.freeze([
|
|
1150
|
+
"path",
|
|
1151
|
+
"visibility-probe",
|
|
1152
|
+
]);
|
|
1153
|
+
export const lightingWavefrontVisibilityProbeModes = Object.freeze([
|
|
1154
|
+
"disabled",
|
|
1155
|
+
"mis-balanced",
|
|
1156
|
+
"exclusive-emissive",
|
|
1157
|
+
]);
|
|
1149
1158
|
export const lightingWavefrontTerminalHitTypes = Object.freeze([
|
|
1150
1159
|
"emissive",
|
|
1151
1160
|
"environment",
|
|
@@ -1193,11 +1202,35 @@ export const lightingWavefrontBufferContracts = Object.freeze({
|
|
|
1193
1202
|
createLightingWavefrontField("sourcePixelId", "u32", "Source pixel/sample owner."),
|
|
1194
1203
|
createLightingWavefrontField("sampleId", "u32", "Per-pixel sample slot."),
|
|
1195
1204
|
createLightingWavefrontField("bounce", "u32", "Current bounce depth."),
|
|
1205
|
+
createLightingWavefrontField("mediumRefId", "u32", "Current medium reference."),
|
|
1206
|
+
createLightingWavefrontField(
|
|
1207
|
+
"mediumStackDepth",
|
|
1208
|
+
"u32",
|
|
1209
|
+
"Depth of the bounded nested medium stack."
|
|
1210
|
+
),
|
|
1211
|
+
createLightingWavefrontField(
|
|
1212
|
+
"flags",
|
|
1213
|
+
"u32",
|
|
1214
|
+
"Renderer-owned ray flags. Low bits may encode ray kind metadata."
|
|
1215
|
+
),
|
|
1216
|
+
createLightingWavefrontField(
|
|
1217
|
+
"mediumStack0",
|
|
1218
|
+
"vec4<u32>",
|
|
1219
|
+
"Lower half of the bounded nested medium stack."
|
|
1220
|
+
),
|
|
1221
|
+
createLightingWavefrontField(
|
|
1222
|
+
"mediumStack1",
|
|
1223
|
+
"vec4<u32>",
|
|
1224
|
+
"Upper half of the bounded nested medium stack."
|
|
1225
|
+
),
|
|
1226
|
+
createLightingWavefrontField(
|
|
1227
|
+
"spectralState",
|
|
1228
|
+
"vec4<f32>",
|
|
1229
|
+
"Spectral transport payload for wavelength-driven reference validation."
|
|
1230
|
+
),
|
|
1196
1231
|
createLightingWavefrontField("origin", "vec3<f32>", "Ray origin."),
|
|
1197
1232
|
createLightingWavefrontField("direction", "vec3<f32>", "Normalized ray direction."),
|
|
1198
1233
|
createLightingWavefrontField("throughput", "vec3<f32>", "Accumulated path throughput."),
|
|
1199
|
-
createLightingWavefrontField("mediumRefId", "u32", "Current medium reference."),
|
|
1200
|
-
createLightingWavefrontField("flags", "u32", "Renderer-owned ray flags."),
|
|
1201
1234
|
]
|
|
1202
1235
|
),
|
|
1203
1236
|
hit: createLightingWavefrontRecordContract(
|
|
@@ -1288,6 +1321,21 @@ const wavefrontEventKinds = Object.freeze([
|
|
|
1288
1321
|
"transparency",
|
|
1289
1322
|
"terminate",
|
|
1290
1323
|
]);
|
|
1324
|
+
const wavefrontRayKindFlagMask = 0x3;
|
|
1325
|
+
const wavefrontRayKindFlagValues = Object.freeze({
|
|
1326
|
+
path: 0,
|
|
1327
|
+
"visibility-probe": 1,
|
|
1328
|
+
});
|
|
1329
|
+
|
|
1330
|
+
function normalizeWavefrontRayKind(value) {
|
|
1331
|
+
return lightingWavefrontRayKinds.includes(value) ? value : "path";
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
function normalizeWavefrontVisibilityProbeMode(value) {
|
|
1335
|
+
return lightingWavefrontVisibilityProbeModes.includes(value)
|
|
1336
|
+
? value
|
|
1337
|
+
: "disabled";
|
|
1338
|
+
}
|
|
1291
1339
|
|
|
1292
1340
|
function normalizeWavefrontHitType(value) {
|
|
1293
1341
|
return lightingWavefrontHitTypes.includes(value) ? value : "surface";
|
|
@@ -1375,6 +1423,137 @@ function refractDirection(direction, normal, etaRatio) {
|
|
|
1375
1423
|
return normalizeDirection(addVec3(rOutPerp, rOutParallel), direction);
|
|
1376
1424
|
}
|
|
1377
1425
|
|
|
1426
|
+
function normalizeMediumRefId(value) {
|
|
1427
|
+
const mediumRefId = Math.max(0, Math.trunc(readFinite(value, 0)));
|
|
1428
|
+
return Number.isFinite(mediumRefId) ? mediumRefId : 0;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
function normalizeMediumStack(value) {
|
|
1432
|
+
if (!Array.isArray(value)) {
|
|
1433
|
+
return [];
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
return value
|
|
1437
|
+
.map((entry) => normalizeMediumRefId(entry))
|
|
1438
|
+
.filter((entry, index, stack) => entry > 0 && stack.indexOf(entry) === index)
|
|
1439
|
+
.slice(0, 4);
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
function createWavefrontMediumStatePayload(currentMediumRefId, stack) {
|
|
1443
|
+
const normalizedStack = normalizeMediumStack(stack);
|
|
1444
|
+
const stackSlots = [0, 0, 0, 0];
|
|
1445
|
+
normalizedStack.forEach((entry, index) => {
|
|
1446
|
+
stackSlots[index] = entry;
|
|
1447
|
+
});
|
|
1448
|
+
return Object.freeze({
|
|
1449
|
+
currentMediumRefId,
|
|
1450
|
+
stackDepth: normalizedStack.length,
|
|
1451
|
+
stack: Object.freeze(normalizedStack),
|
|
1452
|
+
stackSlots: Object.freeze(stackSlots),
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
export function evaluateWavefrontMediumState(options = {}) {
|
|
1457
|
+
const currentMediumRefId = normalizeMediumRefId(
|
|
1458
|
+
options.currentMediumRefId ?? options.mediumRefId
|
|
1459
|
+
);
|
|
1460
|
+
const surfaceMediumRefId = normalizeMediumRefId(options.surfaceMediumRefId);
|
|
1461
|
+
const stack = normalizeMediumStack(options.mediumStack);
|
|
1462
|
+
const frontFace = options.frontFace !== false;
|
|
1463
|
+
const eventKind =
|
|
1464
|
+
normalizeWavefrontEventKind(options.eventKind) ?? "transparency";
|
|
1465
|
+
|
|
1466
|
+
if (
|
|
1467
|
+
surfaceMediumRefId === 0 ||
|
|
1468
|
+
(eventKind !== "refraction" && eventKind !== "transparency")
|
|
1469
|
+
) {
|
|
1470
|
+
return Object.freeze({
|
|
1471
|
+
...createWavefrontMediumStatePayload(currentMediumRefId, stack),
|
|
1472
|
+
enteredMediumRefId: 0,
|
|
1473
|
+
exitedMediumRefId: 0,
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
let nextStack = [...stack];
|
|
1478
|
+
let nextMediumRefId = currentMediumRefId;
|
|
1479
|
+
let enteredMediumRefId = 0;
|
|
1480
|
+
let exitedMediumRefId = 0;
|
|
1481
|
+
const stackTop = nextStack.at(-1) ?? 0;
|
|
1482
|
+
|
|
1483
|
+
if (frontFace) {
|
|
1484
|
+
if (stackTop !== surfaceMediumRefId) {
|
|
1485
|
+
nextStack.push(surfaceMediumRefId);
|
|
1486
|
+
nextStack = nextStack.slice(-4);
|
|
1487
|
+
}
|
|
1488
|
+
nextMediumRefId = surfaceMediumRefId;
|
|
1489
|
+
enteredMediumRefId = surfaceMediumRefId;
|
|
1490
|
+
} else if (stackTop === surfaceMediumRefId) {
|
|
1491
|
+
nextStack.pop();
|
|
1492
|
+
nextMediumRefId = nextStack.at(-1) ?? 0;
|
|
1493
|
+
exitedMediumRefId = surfaceMediumRefId;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
return Object.freeze({
|
|
1497
|
+
...createWavefrontMediumStatePayload(nextMediumRefId, nextStack),
|
|
1498
|
+
enteredMediumRefId,
|
|
1499
|
+
exitedMediumRefId,
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
function encodeWavefrontRayFlags(flags, rayKind) {
|
|
1504
|
+
const normalizedFlags = Math.max(0, Math.trunc(readFinite(flags, 0)));
|
|
1505
|
+
const rayKindValue = wavefrontRayKindFlagValues[rayKind];
|
|
1506
|
+
return (normalizedFlags & ~wavefrontRayKindFlagMask) | rayKindValue;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
export function createWavefrontRayPayload(options = {}) {
|
|
1510
|
+
const rayKind = normalizeWavefrontRayKind(options.rayKind);
|
|
1511
|
+
const mediumState = evaluateWavefrontMediumState({
|
|
1512
|
+
currentMediumRefId: options.mediumRefId,
|
|
1513
|
+
mediumStack: options.mediumStack,
|
|
1514
|
+
});
|
|
1515
|
+
const spectralState = Object.freeze(
|
|
1516
|
+
normalizeVec3(options.spectralState, [550, 1, 0]).concat(
|
|
1517
|
+
readFinite(options.spectralWeight, 0)
|
|
1518
|
+
)
|
|
1519
|
+
);
|
|
1520
|
+
const mediumStack0 = Object.freeze([
|
|
1521
|
+
mediumState.stackSlots[0],
|
|
1522
|
+
mediumState.stackSlots[1],
|
|
1523
|
+
mediumState.stackSlots[2],
|
|
1524
|
+
mediumState.stackSlots[3],
|
|
1525
|
+
]);
|
|
1526
|
+
const mediumStack1 = Object.freeze([0, 0, 0, 0]);
|
|
1527
|
+
return Object.freeze({
|
|
1528
|
+
rayId: Math.max(0, Math.trunc(readFinite(options.rayId, 0))),
|
|
1529
|
+
parentRayId: Math.max(0, Math.trunc(readFinite(options.parentRayId, 0))),
|
|
1530
|
+
sourcePixelId: Math.max(0, Math.trunc(readFinite(options.sourcePixelId, 0))),
|
|
1531
|
+
sampleId: Math.max(0, Math.trunc(readFinite(options.sampleId, 0))),
|
|
1532
|
+
bounce: Math.max(0, Math.trunc(readFinite(options.bounce, 0))),
|
|
1533
|
+
origin: Object.freeze(normalizeVec3(options.origin, [0, 0, 0])),
|
|
1534
|
+
direction: Object.freeze(normalizeDirection(options.direction, [0, 0, -1])),
|
|
1535
|
+
throughput: Object.freeze(
|
|
1536
|
+
saturateVec3(normalizeVec3(options.throughput, [1, 1, 1]))
|
|
1537
|
+
),
|
|
1538
|
+
mediumRefId: mediumState.currentMediumRefId,
|
|
1539
|
+
mediumStackDepth: mediumState.stackDepth,
|
|
1540
|
+
mediumStack: mediumState.stack,
|
|
1541
|
+
mediumStackSlots: mediumState.stackSlots,
|
|
1542
|
+
mediumStack0,
|
|
1543
|
+
mediumStack1,
|
|
1544
|
+
spectralState,
|
|
1545
|
+
rayKind,
|
|
1546
|
+
flags: encodeWavefrontRayFlags(options.flags, rayKind),
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
export function createWavefrontVisibilityProbeRay(options = {}) {
|
|
1551
|
+
return createWavefrontRayPayload({
|
|
1552
|
+
...options,
|
|
1553
|
+
rayKind: "visibility-probe",
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1378
1557
|
export function createWavefrontLightingPlan(options = {}) {
|
|
1379
1558
|
const maxDepth = Math.max(1, Math.trunc(readFinite(options.maxDepth, 4)));
|
|
1380
1559
|
const queueCapacity = Math.max(
|
|
@@ -1382,6 +1561,10 @@ export function createWavefrontLightingPlan(options = {}) {
|
|
|
1382
1561
|
Math.trunc(readFinite(options.queueCapacity, 4096))
|
|
1383
1562
|
);
|
|
1384
1563
|
const explicitLightSampling = Boolean(options.explicitLightSampling);
|
|
1564
|
+
const visibilityProbeMode = normalizeWavefrontVisibilityProbeMode(
|
|
1565
|
+
options.visibilityProbeMode ??
|
|
1566
|
+
(explicitLightSampling ? "mis-balanced" : "disabled")
|
|
1567
|
+
);
|
|
1385
1568
|
const accumulationResetEpoch = Math.max(
|
|
1386
1569
|
0,
|
|
1387
1570
|
Math.trunc(readFinite(options.accumulationResetEpoch, 0))
|
|
@@ -1392,6 +1575,8 @@ export function createWavefrontLightingPlan(options = {}) {
|
|
|
1392
1575
|
maxDepth,
|
|
1393
1576
|
queueCapacity,
|
|
1394
1577
|
explicitLightSampling,
|
|
1578
|
+
visibilityProbeMode,
|
|
1579
|
+
rayKinds: lightingWavefrontRayKinds,
|
|
1395
1580
|
accumulationResetEpoch,
|
|
1396
1581
|
queueLayout: Object.freeze({
|
|
1397
1582
|
strategy: lightingWavefrontQueuePairStrategy,
|
|
@@ -1431,6 +1616,7 @@ export function createWavefrontLightingPlan(options = {}) {
|
|
|
1431
1616
|
writes: Object.freeze(["ray"]),
|
|
1432
1617
|
continuationHitTypes: lightingWavefrontContinuationHitTypes,
|
|
1433
1618
|
explicitLightSampling,
|
|
1619
|
+
visibilityProbeMode,
|
|
1434
1620
|
}),
|
|
1435
1621
|
]),
|
|
1436
1622
|
});
|
|
@@ -1498,7 +1684,7 @@ export function evaluateWavefrontContinuationEvent(options = {}) {
|
|
|
1498
1684
|
const opacity = clampUnit(options.opacity, 1);
|
|
1499
1685
|
const refractiveIndex = Math.max(1, readFinite(options.refractiveIndex ?? options.ior, 1.45));
|
|
1500
1686
|
const transmissionStrength = Math.max(...transmission);
|
|
1501
|
-
|
|
1687
|
+
const requestedEventKind =
|
|
1502
1688
|
normalizeWavefrontEventKind(options.eventKind) ??
|
|
1503
1689
|
(hitType === "transparent" || opacity < 0.999
|
|
1504
1690
|
? "transparency"
|
|
@@ -1507,6 +1693,8 @@ export function evaluateWavefrontContinuationEvent(options = {}) {
|
|
|
1507
1693
|
: metalness >= 0.5 || roughness <= 0.2
|
|
1508
1694
|
? "reflection"
|
|
1509
1695
|
: "diffuse");
|
|
1696
|
+
let eventKind = requestedEventKind;
|
|
1697
|
+
let totalInternalReflection = false;
|
|
1510
1698
|
|
|
1511
1699
|
let nextDirection = incomingDirection;
|
|
1512
1700
|
let attenuation;
|
|
@@ -1519,10 +1707,20 @@ export function evaluateWavefrontContinuationEvent(options = {}) {
|
|
|
1519
1707
|
attenuation = mixVec3([0.04, 0.04, 0.04], albedo, metalness);
|
|
1520
1708
|
} else if (eventKind === "refraction") {
|
|
1521
1709
|
const etaRatio = frontFace ? 1 / refractiveIndex : refractiveIndex;
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1710
|
+
const refractedDirection = refractDirection(
|
|
1711
|
+
incomingDirection,
|
|
1712
|
+
orientedNormal,
|
|
1713
|
+
etaRatio
|
|
1714
|
+
);
|
|
1715
|
+
if (refractedDirection) {
|
|
1716
|
+
nextDirection = refractedDirection;
|
|
1717
|
+
attenuation = transmissionStrength > 0.001 ? transmission : [1, 1, 1];
|
|
1718
|
+
} else {
|
|
1719
|
+
totalInternalReflection = true;
|
|
1720
|
+
eventKind = "reflection";
|
|
1721
|
+
nextDirection = reflectDirection(incomingDirection, orientedNormal);
|
|
1722
|
+
attenuation = mixVec3([0.04, 0.04, 0.04], albedo, metalness);
|
|
1723
|
+
}
|
|
1526
1724
|
} else if (eventKind === "transparency") {
|
|
1527
1725
|
nextDirection = incomingDirection;
|
|
1528
1726
|
const transparencyWeight = Math.max(1 - opacity, transmissionStrength, 0.05);
|
|
@@ -1540,18 +1738,174 @@ export function evaluateWavefrontContinuationEvent(options = {}) {
|
|
|
1540
1738
|
const nextThroughput = multiplyVec3(throughput, saturateVec3(attenuation));
|
|
1541
1739
|
const continueTracing =
|
|
1542
1740
|
eventKind !== "terminate" && colorLuminance(nextThroughput) > 0.0001;
|
|
1741
|
+
const mediumState = evaluateWavefrontMediumState({
|
|
1742
|
+
currentMediumRefId: options.currentMediumRefId ?? options.mediumRefId,
|
|
1743
|
+
surfaceMediumRefId: options.surfaceMediumRefId,
|
|
1744
|
+
mediumStack: options.mediumStack,
|
|
1745
|
+
frontFace,
|
|
1746
|
+
eventKind,
|
|
1747
|
+
});
|
|
1543
1748
|
|
|
1544
1749
|
return Object.freeze({
|
|
1545
1750
|
hitType,
|
|
1751
|
+
requestedEventKind,
|
|
1546
1752
|
eventKind,
|
|
1547
1753
|
continueTracing,
|
|
1754
|
+
totalInternalReflection,
|
|
1548
1755
|
nextDirection: Object.freeze(nextDirection),
|
|
1549
1756
|
attenuation: Object.freeze(saturateVec3(attenuation)),
|
|
1550
1757
|
nextThroughput: Object.freeze(nextThroughput),
|
|
1758
|
+
mediumState,
|
|
1551
1759
|
explicitLightSamplingEnabled: Boolean(options.explicitLightSampling),
|
|
1552
1760
|
});
|
|
1553
1761
|
}
|
|
1554
1762
|
|
|
1763
|
+
export function evaluateWavefrontVisibilityProbe(options = {}) {
|
|
1764
|
+
const probeMode = normalizeWavefrontVisibilityProbeMode(
|
|
1765
|
+
options.probeMode ??
|
|
1766
|
+
(options.explicitLightSampling ? "mis-balanced" : "disabled")
|
|
1767
|
+
);
|
|
1768
|
+
const probeRay = createWavefrontVisibilityProbeRay({
|
|
1769
|
+
...options.probeRay,
|
|
1770
|
+
throughput: options.throughput ?? options.probeRay?.throughput,
|
|
1771
|
+
direction: options.direction ?? options.probeRay?.direction,
|
|
1772
|
+
mediumRefId: options.currentMediumRefId ?? options.probeRay?.mediumRefId,
|
|
1773
|
+
mediumStack: options.mediumStack ?? options.probeRay?.mediumStack,
|
|
1774
|
+
});
|
|
1775
|
+
const transparentSegments = Array.isArray(options.transparentSegments)
|
|
1776
|
+
? options.transparentSegments
|
|
1777
|
+
: [];
|
|
1778
|
+
const transmittance = transparentSegments.reduce(
|
|
1779
|
+
(current, segment) =>
|
|
1780
|
+
multiplyVec3(current, saturateVec3(normalizeVec3(segment, [1, 1, 1]))),
|
|
1781
|
+
[1, 1, 1]
|
|
1782
|
+
);
|
|
1783
|
+
const emissiveRadiance = saturateVec3(
|
|
1784
|
+
normalizeVec3(options.emissiveRadiance, [0, 0, 0])
|
|
1785
|
+
);
|
|
1786
|
+
const environmentRadiance = saturateVec3(
|
|
1787
|
+
normalizeVec3(options.environmentRadiance, [0, 0, 0])
|
|
1788
|
+
);
|
|
1789
|
+
const activeEmissiveRadiance = saturateVec3(
|
|
1790
|
+
normalizeVec3(options.activeEmissiveRadiance, [0, 0, 0])
|
|
1791
|
+
);
|
|
1792
|
+
const prefersEnvironment = Boolean(options.prefersEnvironment);
|
|
1793
|
+
const sourceRadiance =
|
|
1794
|
+
prefersEnvironment || colorLuminance(emissiveRadiance) <= 0.000001
|
|
1795
|
+
? environmentRadiance
|
|
1796
|
+
: emissiveRadiance;
|
|
1797
|
+
const rawContribution = multiplyVec3(
|
|
1798
|
+
probeRay.throughput,
|
|
1799
|
+
multiplyVec3(sourceRadiance, transmittance)
|
|
1800
|
+
);
|
|
1801
|
+
const activeEmissiveVisible =
|
|
1802
|
+
colorLuminance(activeEmissiveRadiance) > 0.000001;
|
|
1803
|
+
const misWeight =
|
|
1804
|
+
probeMode === "mis-balanced" && activeEmissiveVisible ? 0.5 : 1;
|
|
1805
|
+
const contribution =
|
|
1806
|
+
probeMode === "exclusive-emissive" && activeEmissiveVisible
|
|
1807
|
+
? [0, 0, 0]
|
|
1808
|
+
: scaleVec3(rawContribution, misWeight);
|
|
1809
|
+
|
|
1810
|
+
return Object.freeze({
|
|
1811
|
+
probeMode,
|
|
1812
|
+
probeRay,
|
|
1813
|
+
transmittance: Object.freeze(transmittance),
|
|
1814
|
+
misWeight,
|
|
1815
|
+
doubleCountPrevented:
|
|
1816
|
+
activeEmissiveVisible && probeMode !== "disabled",
|
|
1817
|
+
contribution: Object.freeze(contribution),
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
export function evaluateWavefrontMaterialReference(options = {}) {
|
|
1822
|
+
const material = Object.freeze({
|
|
1823
|
+
albedo: Object.freeze(
|
|
1824
|
+
saturateVec3(normalizeVec3(options.albedo, [0.8, 0.8, 0.8]))
|
|
1825
|
+
),
|
|
1826
|
+
emission: Object.freeze(
|
|
1827
|
+
saturateVec3(normalizeVec3(options.emission, [0, 0, 0]))
|
|
1828
|
+
),
|
|
1829
|
+
roughness: clampUnit(options.roughness, 0.5),
|
|
1830
|
+
metalness: clampUnit(options.metalness, 0),
|
|
1831
|
+
opacity: clampUnit(options.opacity, 1),
|
|
1832
|
+
transmission: Object.freeze(
|
|
1833
|
+
saturateVec3(normalizeVec3(options.transmission, [0, 0, 0]))
|
|
1834
|
+
),
|
|
1835
|
+
refractiveIndex: Math.max(
|
|
1836
|
+
1,
|
|
1837
|
+
readFinite(options.refractiveIndex ?? options.ior, 1.45)
|
|
1838
|
+
),
|
|
1839
|
+
});
|
|
1840
|
+
const continuation = evaluateWavefrontContinuationEvent({
|
|
1841
|
+
...options,
|
|
1842
|
+
albedo: material.albedo,
|
|
1843
|
+
roughness: material.roughness,
|
|
1844
|
+
metalness: material.metalness,
|
|
1845
|
+
opacity: material.opacity,
|
|
1846
|
+
transmission: material.transmission,
|
|
1847
|
+
refractiveIndex: material.refractiveIndex,
|
|
1848
|
+
});
|
|
1849
|
+
const terminal = evaluateWavefrontTerminalRadiance({
|
|
1850
|
+
...options,
|
|
1851
|
+
emission: material.emission,
|
|
1852
|
+
});
|
|
1853
|
+
|
|
1854
|
+
return Object.freeze({
|
|
1855
|
+
material,
|
|
1856
|
+
terminal,
|
|
1857
|
+
continuation,
|
|
1858
|
+
throughputUpdate: continuation.nextThroughput,
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
export function createWavefrontReferenceFixture(options = {}) {
|
|
1863
|
+
const tolerance = Math.max(0.0001, readFinite(options.tolerance, 0.0005));
|
|
1864
|
+
const ray = createWavefrontRayPayload({
|
|
1865
|
+
rayId: options.rayId,
|
|
1866
|
+
parentRayId: options.parentRayId,
|
|
1867
|
+
sourcePixelId: options.sourcePixelId,
|
|
1868
|
+
sampleId: options.sampleId,
|
|
1869
|
+
bounce: options.bounceIndex ?? options.bounce,
|
|
1870
|
+
origin: options.origin,
|
|
1871
|
+
direction: options.direction ?? scaleVec3(options.viewDirection ?? [0, 0, 1], -1),
|
|
1872
|
+
throughput: options.throughput,
|
|
1873
|
+
mediumRefId: options.currentMediumRefId ?? options.mediumRefId,
|
|
1874
|
+
mediumStack: options.mediumStack,
|
|
1875
|
+
});
|
|
1876
|
+
const reference = evaluateWavefrontMaterialReference(options);
|
|
1877
|
+
const visibilityProbe =
|
|
1878
|
+
options.visibilityProbe === undefined
|
|
1879
|
+
? null
|
|
1880
|
+
: evaluateWavefrontVisibilityProbe({
|
|
1881
|
+
...options.visibilityProbe,
|
|
1882
|
+
throughput: options.visibilityProbe.throughput ?? ray.throughput,
|
|
1883
|
+
});
|
|
1884
|
+
const accumulationRadiance = addVec3(
|
|
1885
|
+
reference.terminal.radiance,
|
|
1886
|
+
visibilityProbe?.contribution ?? [0, 0, 0]
|
|
1887
|
+
);
|
|
1888
|
+
|
|
1889
|
+
return Object.freeze({
|
|
1890
|
+
tolerance,
|
|
1891
|
+
ray,
|
|
1892
|
+
material: reference.material,
|
|
1893
|
+
continuation: reference.continuation,
|
|
1894
|
+
terminal: reference.terminal,
|
|
1895
|
+
visibilityProbe,
|
|
1896
|
+
accumulation: Object.freeze({
|
|
1897
|
+
sourcePixelId: ray.sourcePixelId,
|
|
1898
|
+
sampleCount: reference.terminal.terminated ? 1 : 0,
|
|
1899
|
+
radiance: Object.freeze(accumulationRadiance),
|
|
1900
|
+
throughput: reference.continuation.nextThroughput,
|
|
1901
|
+
resetEpoch: Math.max(
|
|
1902
|
+
0,
|
|
1903
|
+
Math.trunc(readFinite(options.accumulationResetEpoch, 0))
|
|
1904
|
+
),
|
|
1905
|
+
}),
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1555
1909
|
const lightingImportanceLevels = Object.freeze([
|
|
1556
1910
|
"low",
|
|
1557
1911
|
"medium",
|
|
@@ -13,6 +13,10 @@ const EVENT_KIND_REFRACTION: u32 = 2u;
|
|
|
13
13
|
const EVENT_KIND_TRANSPARENCY: u32 = 3u;
|
|
14
14
|
const EVENT_KIND_TERMINATE: u32 = 4u;
|
|
15
15
|
|
|
16
|
+
const RAY_KIND_PATH: u32 = 0u;
|
|
17
|
+
const RAY_KIND_VISIBILITY_PROBE: u32 = 1u;
|
|
18
|
+
const RAY_KIND_MASK: u32 = 0x3u;
|
|
19
|
+
|
|
16
20
|
const LIGHTING_EPSILON: f32 = 0.0001;
|
|
17
21
|
const LIGHTING_INV_PI: f32 = 0.3183098861837907;
|
|
18
22
|
|
|
@@ -147,6 +151,10 @@ fn is_terminal_hit_type(hit_type: u32) -> bool {
|
|
|
147
151
|
hit_type == HIT_TYPE_MISS;
|
|
148
152
|
}
|
|
149
153
|
|
|
154
|
+
fn ray_kind(flags: u32) -> u32 {
|
|
155
|
+
return flags & RAY_KIND_MASK;
|
|
156
|
+
}
|
|
157
|
+
|
|
150
158
|
fn environment_radiance(direction: vec3<f32>) -> vec3<f32> {
|
|
151
159
|
let upward = saturate_scalar(direction.y * 0.5 + 0.5);
|
|
152
160
|
let directional = mix(
|