@plasius/gpu-lighting 0.2.5 → 0.2.7
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 +35 -3
- package/README.md +98 -0
- package/dist/index.cjs +837 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +817 -0
- package/dist/index.js.map +1 -1
- package/dist/techniques/techniques/wavefront/accumulate-terminal-radiance.job.wgsl +61 -0
- package/dist/techniques/techniques/wavefront/prelude.wgsl +237 -0
- package/dist/techniques/techniques/wavefront/scatter-continuations.job.wgsl +136 -0
- package/package.json +2 -1
- package/src/index.js +889 -0
- package/src/techniques/wavefront/accumulate-terminal-radiance.job.wgsl +61 -0
- package/src/techniques/wavefront/prelude.wgsl +237 -0
- package/src/techniques/wavefront/scatter-continuations.job.wgsl +136 -0
package/src/index.js
CHANGED
|
@@ -40,6 +40,15 @@ const techniqueSpecs = {
|
|
|
40
40
|
denoise: "denoise.job.wgsl",
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
|
+
wavefront: {
|
|
44
|
+
description:
|
|
45
|
+
"Renderer-aligned wavefront lighting jobs for terminal radiance and continuation scattering.",
|
|
46
|
+
prelude: "prelude.wgsl",
|
|
47
|
+
jobs: {
|
|
48
|
+
accumulateTerminalRadiance: "accumulate-terminal-radiance.job.wgsl",
|
|
49
|
+
scatterContinuations: "scatter-continuations.job.wgsl",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
43
52
|
volumetrics: {
|
|
44
53
|
description:
|
|
45
54
|
"Froxel volumetric lighting for fog, shafts, and participating media shadows.",
|
|
@@ -1128,6 +1137,775 @@ export function createWavefrontEnvironmentLightingOptions(options = {}) {
|
|
|
1128
1137
|
});
|
|
1129
1138
|
}
|
|
1130
1139
|
|
|
1140
|
+
export const lightingWavefrontSchemaVersion = 1;
|
|
1141
|
+
export const lightingWavefrontQueuePairStrategy = "ping-pong-active-next";
|
|
1142
|
+
export const lightingWavefrontHitTypes = Object.freeze([
|
|
1143
|
+
"surface",
|
|
1144
|
+
"emissive",
|
|
1145
|
+
"environment",
|
|
1146
|
+
"transparent",
|
|
1147
|
+
"miss",
|
|
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
|
+
]);
|
|
1158
|
+
export const lightingWavefrontTerminalHitTypes = Object.freeze([
|
|
1159
|
+
"emissive",
|
|
1160
|
+
"environment",
|
|
1161
|
+
"miss",
|
|
1162
|
+
]);
|
|
1163
|
+
export const lightingWavefrontContinuationHitTypes = Object.freeze([
|
|
1164
|
+
"surface",
|
|
1165
|
+
"transparent",
|
|
1166
|
+
]);
|
|
1167
|
+
export const lightingWavefrontPassOrder = Object.freeze([
|
|
1168
|
+
"accumulateTerminalRadiance",
|
|
1169
|
+
"scatterContinuations",
|
|
1170
|
+
]);
|
|
1171
|
+
export const lightingRequiredRendererWavefrontPassOrder = Object.freeze([
|
|
1172
|
+
"generatePrimaryRays",
|
|
1173
|
+
"intersectActiveQueue",
|
|
1174
|
+
"resolveSurfaceRecords",
|
|
1175
|
+
"accumulateTerminalRadiance",
|
|
1176
|
+
"scatterContinuations",
|
|
1177
|
+
"compactAndSwapQueues",
|
|
1178
|
+
]);
|
|
1179
|
+
|
|
1180
|
+
function createLightingWavefrontField(name, type, description) {
|
|
1181
|
+
return Object.freeze({
|
|
1182
|
+
name,
|
|
1183
|
+
type,
|
|
1184
|
+
description,
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
function createLightingWavefrontRecordContract(recordName, fields) {
|
|
1189
|
+
return Object.freeze({
|
|
1190
|
+
schemaVersion: lightingWavefrontSchemaVersion,
|
|
1191
|
+
recordName,
|
|
1192
|
+
fields: Object.freeze(fields),
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
export const lightingWavefrontBufferContracts = Object.freeze({
|
|
1197
|
+
ray: createLightingWavefrontRecordContract(
|
|
1198
|
+
"RayRecord",
|
|
1199
|
+
[
|
|
1200
|
+
createLightingWavefrontField("rayId", "u32", "Stable ray identifier."),
|
|
1201
|
+
createLightingWavefrontField("parentRayId", "u32", "Parent ray identifier."),
|
|
1202
|
+
createLightingWavefrontField("sourcePixelId", "u32", "Source pixel/sample owner."),
|
|
1203
|
+
createLightingWavefrontField("sampleId", "u32", "Per-pixel sample slot."),
|
|
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
|
+
),
|
|
1231
|
+
createLightingWavefrontField("origin", "vec3<f32>", "Ray origin."),
|
|
1232
|
+
createLightingWavefrontField("direction", "vec3<f32>", "Normalized ray direction."),
|
|
1233
|
+
createLightingWavefrontField("throughput", "vec3<f32>", "Accumulated path throughput."),
|
|
1234
|
+
]
|
|
1235
|
+
),
|
|
1236
|
+
hit: createLightingWavefrontRecordContract(
|
|
1237
|
+
"HitRecord",
|
|
1238
|
+
[
|
|
1239
|
+
createLightingWavefrontField("rayId", "u32", "Stable ray identifier."),
|
|
1240
|
+
createLightingWavefrontField("sourcePixelId", "u32", "Source pixel/sample owner."),
|
|
1241
|
+
createLightingWavefrontField("hitType", "u32", "Surface, emissive, environment, transparent, or miss."),
|
|
1242
|
+
createLightingWavefrontField("distance", "f32", "Nearest-hit distance."),
|
|
1243
|
+
createLightingWavefrontField("entityId", "u32", "Owning entity identifier."),
|
|
1244
|
+
createLightingWavefrontField("instanceId", "u32", "Owning instance identifier."),
|
|
1245
|
+
createLightingWavefrontField("primitiveId", "u32", "Primitive identifier."),
|
|
1246
|
+
createLightingWavefrontField("materialId", "u32", "Resolved material identifier."),
|
|
1247
|
+
createLightingWavefrontField("barycentrics", "vec3<f32>", "Triangle barycentrics."),
|
|
1248
|
+
createLightingWavefrontField("uv", "vec2<f32>", "Resolved UV coordinates."),
|
|
1249
|
+
createLightingWavefrontField("geometricNormal", "vec3<f32>", "Geometric surface normal."),
|
|
1250
|
+
createLightingWavefrontField("shadingNormal", "vec3<f32>", "Interpolated shading normal."),
|
|
1251
|
+
createLightingWavefrontField("frontFace", "u32", "Front-face classification."),
|
|
1252
|
+
]
|
|
1253
|
+
),
|
|
1254
|
+
surface: createLightingWavefrontRecordContract(
|
|
1255
|
+
"SurfaceRecord",
|
|
1256
|
+
[
|
|
1257
|
+
createLightingWavefrontField("rayId", "u32", "Stable ray identifier."),
|
|
1258
|
+
createLightingWavefrontField("entityId", "u32", "Owning entity identifier."),
|
|
1259
|
+
createLightingWavefrontField("materialRefId", "u32", "Renderer material reference id."),
|
|
1260
|
+
createLightingWavefrontField("mediumRefId", "u32", "Renderer medium reference id."),
|
|
1261
|
+
createLightingWavefrontField("geometricNormal", "vec3<f32>", "Geometric surface normal."),
|
|
1262
|
+
createLightingWavefrontField("shadingNormal", "vec3<f32>", "Interpolated shading normal."),
|
|
1263
|
+
createLightingWavefrontField("uv", "vec2<f32>", "Resolved UV coordinates."),
|
|
1264
|
+
createLightingWavefrontField("tangentFrame", "mat3x3<f32>", "Resolved tangent frame."),
|
|
1265
|
+
]
|
|
1266
|
+
),
|
|
1267
|
+
materialReference: createLightingWavefrontRecordContract(
|
|
1268
|
+
"MaterialReferenceRecord",
|
|
1269
|
+
[
|
|
1270
|
+
createLightingWavefrontField("materialRefId", "u32", "Lighting-visible material reference id."),
|
|
1271
|
+
createLightingWavefrontField("materialId", "u32", "Source material identifier."),
|
|
1272
|
+
createLightingWavefrontField("shadingModel", "u32", "Renderer shading-model discriminator."),
|
|
1273
|
+
createLightingWavefrontField("textureSetId", "u32", "Resolved texture-set identifier."),
|
|
1274
|
+
createLightingWavefrontField("flags", "u32", "Renderer material flags."),
|
|
1275
|
+
]
|
|
1276
|
+
),
|
|
1277
|
+
mediumReference: createLightingWavefrontRecordContract(
|
|
1278
|
+
"MediumReferenceRecord",
|
|
1279
|
+
[
|
|
1280
|
+
createLightingWavefrontField("mediumRefId", "u32", "Lighting-visible medium reference id."),
|
|
1281
|
+
createLightingWavefrontField("mediumId", "u32", "Source medium identifier."),
|
|
1282
|
+
createLightingWavefrontField("phaseModel", "u32", "Phase-function discriminator."),
|
|
1283
|
+
createLightingWavefrontField("absorption", "vec3<f32>", "Medium absorption coefficients."),
|
|
1284
|
+
createLightingWavefrontField("scattering", "vec3<f32>", "Medium scattering coefficients."),
|
|
1285
|
+
]
|
|
1286
|
+
),
|
|
1287
|
+
accumulation: createLightingWavefrontRecordContract(
|
|
1288
|
+
"AccumulationRecord",
|
|
1289
|
+
[
|
|
1290
|
+
createLightingWavefrontField("sourcePixelId", "u32", "Source pixel/sample owner."),
|
|
1291
|
+
createLightingWavefrontField("sampleCount", "u32", "Accumulated sample count."),
|
|
1292
|
+
createLightingWavefrontField("radiance", "vec3<f32>", "Accumulated radiance."),
|
|
1293
|
+
createLightingWavefrontField("throughput", "vec3<f32>", "Last surviving throughput."),
|
|
1294
|
+
createLightingWavefrontField("resetEpoch", "u32", "Renderer accumulation reset epoch."),
|
|
1295
|
+
]
|
|
1296
|
+
),
|
|
1297
|
+
});
|
|
1298
|
+
|
|
1299
|
+
export const lightingWavefrontTerminationPolicy = Object.freeze({
|
|
1300
|
+
terminalHitTypes: lightingWavefrontTerminalHitTypes,
|
|
1301
|
+
continuationHitTypes: lightingWavefrontContinuationHitTypes,
|
|
1302
|
+
emissive: Object.freeze({
|
|
1303
|
+
action: "accumulate-and-stop",
|
|
1304
|
+
contributesRadiance: true,
|
|
1305
|
+
}),
|
|
1306
|
+
environment: Object.freeze({
|
|
1307
|
+
action: "accumulate-and-stop",
|
|
1308
|
+
contributesRadiance: true,
|
|
1309
|
+
}),
|
|
1310
|
+
miss: Object.freeze({
|
|
1311
|
+
action: "accumulate-environment-or-dark-stop",
|
|
1312
|
+
contributesRadiance: true,
|
|
1313
|
+
}),
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
const defaultWavefrontDarkRadiance = Object.freeze([0.0001, 0.0001, 0.0001]);
|
|
1317
|
+
const wavefrontEventKinds = Object.freeze([
|
|
1318
|
+
"diffuse",
|
|
1319
|
+
"reflection",
|
|
1320
|
+
"refraction",
|
|
1321
|
+
"transparency",
|
|
1322
|
+
"terminate",
|
|
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
|
+
}
|
|
1339
|
+
|
|
1340
|
+
function normalizeWavefrontHitType(value) {
|
|
1341
|
+
return lightingWavefrontHitTypes.includes(value) ? value : "surface";
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
function normalizeWavefrontEventKind(value) {
|
|
1345
|
+
return wavefrontEventKinds.includes(value) ? value : null;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
function normalizeVec3(value, fallback = [0, 0, 0]) {
|
|
1349
|
+
if (!Array.isArray(value) || value.length < 3) {
|
|
1350
|
+
return [...fallback];
|
|
1351
|
+
}
|
|
1352
|
+
return [
|
|
1353
|
+
Number.isFinite(value[0]) ? value[0] : fallback[0],
|
|
1354
|
+
Number.isFinite(value[1]) ? value[1] : fallback[1],
|
|
1355
|
+
Number.isFinite(value[2]) ? value[2] : fallback[2],
|
|
1356
|
+
];
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
function clampUnit(value, fallback = 0) {
|
|
1360
|
+
return Math.max(0, Math.min(1, readFinite(value, fallback)));
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
function saturateVec3(value) {
|
|
1364
|
+
return value.map((component) => Math.max(0, component));
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
function scaleVec3(value, scalar) {
|
|
1368
|
+
return value.map((component) => component * scalar);
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
function addVec3(left, right) {
|
|
1372
|
+
return left.map((component, index) => component + right[index]);
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
function multiplyVec3(left, right) {
|
|
1376
|
+
return left.map((component, index) => component * right[index]);
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
function dotVec3(left, right) {
|
|
1380
|
+
return left[0] * right[0] + left[1] * right[1] + left[2] * right[2];
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
function lengthVec3(value) {
|
|
1384
|
+
return Math.hypot(value[0], value[1], value[2]);
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
function normalizeDirection(value, fallback = [0, 1, 0]) {
|
|
1388
|
+
const vector = normalizeVec3(value, fallback);
|
|
1389
|
+
const length = lengthVec3(vector);
|
|
1390
|
+
if (!Number.isFinite(length) || length <= 0.000001) {
|
|
1391
|
+
return [...fallback];
|
|
1392
|
+
}
|
|
1393
|
+
return vector.map((component) => component / length);
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
function mixVec3(left, right, factor) {
|
|
1397
|
+
return left.map((component, index) =>
|
|
1398
|
+
component * (1 - factor) + right[index] * factor
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
function reflectDirection(direction, normal) {
|
|
1403
|
+
const scale = 2 * dotVec3(direction, normal);
|
|
1404
|
+
return normalizeDirection(
|
|
1405
|
+
[
|
|
1406
|
+
direction[0] - scale * normal[0],
|
|
1407
|
+
direction[1] - scale * normal[1],
|
|
1408
|
+
direction[2] - scale * normal[2],
|
|
1409
|
+
],
|
|
1410
|
+
normal
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
function refractDirection(direction, normal, etaRatio) {
|
|
1415
|
+
const cosTheta = Math.min(-dotVec3(direction, normal), 1);
|
|
1416
|
+
const rOutPerp = scaleVec3(addVec3(direction, scaleVec3(normal, cosTheta)), etaRatio);
|
|
1417
|
+
const rOutPerpLengthSquared = dotVec3(rOutPerp, rOutPerp);
|
|
1418
|
+
const parallelFactor = 1 - rOutPerpLengthSquared;
|
|
1419
|
+
if (parallelFactor <= 0) {
|
|
1420
|
+
return null;
|
|
1421
|
+
}
|
|
1422
|
+
const rOutParallel = scaleVec3(normal, -Math.sqrt(parallelFactor));
|
|
1423
|
+
return normalizeDirection(addVec3(rOutPerp, rOutParallel), direction);
|
|
1424
|
+
}
|
|
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
|
+
|
|
1557
|
+
export function createWavefrontLightingPlan(options = {}) {
|
|
1558
|
+
const maxDepth = Math.max(1, Math.trunc(readFinite(options.maxDepth, 4)));
|
|
1559
|
+
const queueCapacity = Math.max(
|
|
1560
|
+
1,
|
|
1561
|
+
Math.trunc(readFinite(options.queueCapacity, 4096))
|
|
1562
|
+
);
|
|
1563
|
+
const explicitLightSampling = Boolean(options.explicitLightSampling);
|
|
1564
|
+
const visibilityProbeMode = normalizeWavefrontVisibilityProbeMode(
|
|
1565
|
+
options.visibilityProbeMode ??
|
|
1566
|
+
(explicitLightSampling ? "mis-balanced" : "disabled")
|
|
1567
|
+
);
|
|
1568
|
+
const accumulationResetEpoch = Math.max(
|
|
1569
|
+
0,
|
|
1570
|
+
Math.trunc(readFinite(options.accumulationResetEpoch, 0))
|
|
1571
|
+
);
|
|
1572
|
+
|
|
1573
|
+
return Object.freeze({
|
|
1574
|
+
schemaVersion: lightingWavefrontSchemaVersion,
|
|
1575
|
+
maxDepth,
|
|
1576
|
+
queueCapacity,
|
|
1577
|
+
explicitLightSampling,
|
|
1578
|
+
visibilityProbeMode,
|
|
1579
|
+
rayKinds: lightingWavefrontRayKinds,
|
|
1580
|
+
accumulationResetEpoch,
|
|
1581
|
+
queueLayout: Object.freeze({
|
|
1582
|
+
strategy: lightingWavefrontQueuePairStrategy,
|
|
1583
|
+
compactAfterScatter: true,
|
|
1584
|
+
queues: Object.freeze([
|
|
1585
|
+
Object.freeze({ name: "active", role: "current-bounce" }),
|
|
1586
|
+
Object.freeze({ name: "next", role: "next-bounce" }),
|
|
1587
|
+
]),
|
|
1588
|
+
}),
|
|
1589
|
+
bufferContracts: lightingWavefrontBufferContracts,
|
|
1590
|
+
terminationPolicy: lightingWavefrontTerminationPolicy,
|
|
1591
|
+
requiredRendererPassOrder: lightingRequiredRendererWavefrontPassOrder,
|
|
1592
|
+
lightingPasses: Object.freeze([
|
|
1593
|
+
Object.freeze({
|
|
1594
|
+
key: "accumulateTerminalRadiance",
|
|
1595
|
+
stage: "accumulateTerminalRadiance",
|
|
1596
|
+
reads: Object.freeze([
|
|
1597
|
+
"ray",
|
|
1598
|
+
"hit",
|
|
1599
|
+
"surface",
|
|
1600
|
+
"materialReference",
|
|
1601
|
+
"mediumReference",
|
|
1602
|
+
]),
|
|
1603
|
+
writes: Object.freeze(["accumulation"]),
|
|
1604
|
+
terminalHitTypes: lightingWavefrontTerminalHitTypes,
|
|
1605
|
+
}),
|
|
1606
|
+
Object.freeze({
|
|
1607
|
+
key: "scatterContinuations",
|
|
1608
|
+
stage: "scatterContinuations",
|
|
1609
|
+
reads: Object.freeze([
|
|
1610
|
+
"ray",
|
|
1611
|
+
"hit",
|
|
1612
|
+
"surface",
|
|
1613
|
+
"materialReference",
|
|
1614
|
+
"mediumReference",
|
|
1615
|
+
]),
|
|
1616
|
+
writes: Object.freeze(["ray"]),
|
|
1617
|
+
continuationHitTypes: lightingWavefrontContinuationHitTypes,
|
|
1618
|
+
explicitLightSampling,
|
|
1619
|
+
visibilityProbeMode,
|
|
1620
|
+
}),
|
|
1621
|
+
]),
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
export function evaluateWavefrontTerminalRadiance(options = {}) {
|
|
1626
|
+
const hitType = normalizeWavefrontHitType(options.hitType);
|
|
1627
|
+
const throughput = saturateVec3(normalizeVec3(options.throughput, [1, 1, 1]));
|
|
1628
|
+
const emission = saturateVec3(normalizeVec3(options.emission, [0, 0, 0]));
|
|
1629
|
+
const environmentRadiance = saturateVec3(
|
|
1630
|
+
normalizeVec3(options.environmentRadiance, [0, 0, 0])
|
|
1631
|
+
);
|
|
1632
|
+
const missRadiance = saturateVec3(
|
|
1633
|
+
normalizeVec3(options.missRadiance, defaultWavefrontDarkRadiance)
|
|
1634
|
+
);
|
|
1635
|
+
const environmentLuminance = colorLuminance(environmentRadiance);
|
|
1636
|
+
let source = "none";
|
|
1637
|
+
let rawRadiance = [0, 0, 0];
|
|
1638
|
+
|
|
1639
|
+
if (hitType === "emissive") {
|
|
1640
|
+
source = "emissive";
|
|
1641
|
+
rawRadiance = emission;
|
|
1642
|
+
} else if (hitType === "environment") {
|
|
1643
|
+
source = "environment";
|
|
1644
|
+
rawRadiance = environmentRadiance;
|
|
1645
|
+
} else if (hitType === "miss") {
|
|
1646
|
+
source = environmentLuminance > 0.000001 ? "environment" : "dark";
|
|
1647
|
+
rawRadiance = environmentLuminance > 0.000001 ? environmentRadiance : missRadiance;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const radiance = multiplyVec3(throughput, rawRadiance);
|
|
1651
|
+
const terminated = lightingWavefrontTerminalHitTypes.includes(hitType);
|
|
1652
|
+
|
|
1653
|
+
return Object.freeze({
|
|
1654
|
+
hitType,
|
|
1655
|
+
source,
|
|
1656
|
+
terminated,
|
|
1657
|
+
radiance: Object.freeze(radiance),
|
|
1658
|
+
nearDarkSample:
|
|
1659
|
+
source === "dark" && colorLuminance(radiance) <= colorLuminance(defaultWavefrontDarkRadiance),
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
export function evaluateWavefrontContinuationEvent(options = {}) {
|
|
1664
|
+
const hitType = normalizeWavefrontHitType(options.hitType);
|
|
1665
|
+
const bounceIndex = Math.max(0, Math.trunc(readFinite(options.bounceIndex, 0)));
|
|
1666
|
+
const maxDepth = Math.max(1, Math.trunc(readFinite(options.maxDepth, 4)));
|
|
1667
|
+
const throughput = saturateVec3(normalizeVec3(options.throughput, [1, 1, 1]));
|
|
1668
|
+
const albedo = saturateVec3(normalizeVec3(options.albedo, [0.8, 0.8, 0.8]));
|
|
1669
|
+
const transmission = saturateVec3(
|
|
1670
|
+
normalizeVec3(options.transmission, [0, 0, 0])
|
|
1671
|
+
);
|
|
1672
|
+
const shadingNormal = normalizeDirection(options.shadingNormal, [0, 1, 0]);
|
|
1673
|
+
const viewDirection = normalizeDirection(options.viewDirection, [0, 0, 1]);
|
|
1674
|
+
const incomingDirection = normalizeDirection(
|
|
1675
|
+
scaleVec3(viewDirection, -1),
|
|
1676
|
+
[0, 0, -1]
|
|
1677
|
+
);
|
|
1678
|
+
const frontFace = options.frontFace !== false;
|
|
1679
|
+
const orientedNormal = frontFace
|
|
1680
|
+
? shadingNormal
|
|
1681
|
+
: scaleVec3(shadingNormal, -1);
|
|
1682
|
+
const metalness = clampUnit(options.metalness, 0);
|
|
1683
|
+
const roughness = clampUnit(options.roughness, 0.5);
|
|
1684
|
+
const opacity = clampUnit(options.opacity, 1);
|
|
1685
|
+
const refractiveIndex = Math.max(1, readFinite(options.refractiveIndex ?? options.ior, 1.45));
|
|
1686
|
+
const transmissionStrength = Math.max(...transmission);
|
|
1687
|
+
const requestedEventKind =
|
|
1688
|
+
normalizeWavefrontEventKind(options.eventKind) ??
|
|
1689
|
+
(hitType === "transparent" || opacity < 0.999
|
|
1690
|
+
? "transparency"
|
|
1691
|
+
: transmissionStrength > 0.001
|
|
1692
|
+
? "refraction"
|
|
1693
|
+
: metalness >= 0.5 || roughness <= 0.2
|
|
1694
|
+
? "reflection"
|
|
1695
|
+
: "diffuse");
|
|
1696
|
+
let eventKind = requestedEventKind;
|
|
1697
|
+
let totalInternalReflection = false;
|
|
1698
|
+
|
|
1699
|
+
let nextDirection = incomingDirection;
|
|
1700
|
+
let attenuation;
|
|
1701
|
+
|
|
1702
|
+
if (!lightingWavefrontContinuationHitTypes.includes(hitType) || bounceIndex >= maxDepth - 1) {
|
|
1703
|
+
eventKind = "terminate";
|
|
1704
|
+
attenuation = [0, 0, 0];
|
|
1705
|
+
} else if (eventKind === "reflection") {
|
|
1706
|
+
nextDirection = reflectDirection(incomingDirection, orientedNormal);
|
|
1707
|
+
attenuation = mixVec3([0.04, 0.04, 0.04], albedo, metalness);
|
|
1708
|
+
} else if (eventKind === "refraction") {
|
|
1709
|
+
const etaRatio = frontFace ? 1 / refractiveIndex : refractiveIndex;
|
|
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
|
+
}
|
|
1724
|
+
} else if (eventKind === "transparency") {
|
|
1725
|
+
nextDirection = incomingDirection;
|
|
1726
|
+
const transparencyWeight = Math.max(1 - opacity, transmissionStrength, 0.05);
|
|
1727
|
+
attenuation = transmissionStrength > 0.001
|
|
1728
|
+
? transmission
|
|
1729
|
+
: [transparencyWeight, transparencyWeight, transparencyWeight];
|
|
1730
|
+
} else {
|
|
1731
|
+
nextDirection = normalizeDirection(
|
|
1732
|
+
addVec3(orientedNormal, albedo.map((component) => component - 0.5)),
|
|
1733
|
+
orientedNormal
|
|
1734
|
+
);
|
|
1735
|
+
attenuation = scaleVec3(albedo, Math.max(0.05, 1 - metalness));
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
const nextThroughput = multiplyVec3(throughput, saturateVec3(attenuation));
|
|
1739
|
+
const continueTracing =
|
|
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
|
+
});
|
|
1748
|
+
|
|
1749
|
+
return Object.freeze({
|
|
1750
|
+
hitType,
|
|
1751
|
+
requestedEventKind,
|
|
1752
|
+
eventKind,
|
|
1753
|
+
continueTracing,
|
|
1754
|
+
totalInternalReflection,
|
|
1755
|
+
nextDirection: Object.freeze(nextDirection),
|
|
1756
|
+
attenuation: Object.freeze(saturateVec3(attenuation)),
|
|
1757
|
+
nextThroughput: Object.freeze(nextThroughput),
|
|
1758
|
+
mediumState,
|
|
1759
|
+
explicitLightSamplingEnabled: Boolean(options.explicitLightSampling),
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
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
|
+
|
|
1131
1909
|
const lightingImportanceLevels = Object.freeze([
|
|
1132
1910
|
"low",
|
|
1133
1911
|
"medium",
|
|
@@ -1725,6 +2503,91 @@ const lightingWorkerSpecPresets = {
|
|
|
1725
2503
|
},
|
|
1726
2504
|
},
|
|
1727
2505
|
},
|
|
2506
|
+
wavefront: {
|
|
2507
|
+
suggestedAllocationIds: [
|
|
2508
|
+
"lighting.wavefront.active-queue",
|
|
2509
|
+
"lighting.wavefront.next-queue",
|
|
2510
|
+
"lighting.wavefront.accumulation",
|
|
2511
|
+
],
|
|
2512
|
+
jobs: {
|
|
2513
|
+
accumulateTerminalRadiance: {
|
|
2514
|
+
domain: "lighting",
|
|
2515
|
+
importance: "critical",
|
|
2516
|
+
levels: buildWorkerBudgetLevels(
|
|
2517
|
+
"lighting.wavefront.accumulateTerminalRadiance",
|
|
2518
|
+
lightingWorkerQueueClass,
|
|
2519
|
+
{
|
|
2520
|
+
low: {
|
|
2521
|
+
estimatedCostMs: 0.7,
|
|
2522
|
+
maxDispatchesPerFrame: 1,
|
|
2523
|
+
maxJobsPerDispatch: 32,
|
|
2524
|
+
cadenceDivisor: 2,
|
|
2525
|
+
workgroupScale: 0.5,
|
|
2526
|
+
maxQueueDepth: 96,
|
|
2527
|
+
},
|
|
2528
|
+
medium: {
|
|
2529
|
+
estimatedCostMs: 1.2,
|
|
2530
|
+
maxDispatchesPerFrame: 1,
|
|
2531
|
+
maxJobsPerDispatch: 64,
|
|
2532
|
+
cadenceDivisor: 1,
|
|
2533
|
+
workgroupScale: 0.75,
|
|
2534
|
+
maxQueueDepth: 192,
|
|
2535
|
+
},
|
|
2536
|
+
high: {
|
|
2537
|
+
estimatedCostMs: 1.8,
|
|
2538
|
+
maxDispatchesPerFrame: 2,
|
|
2539
|
+
maxJobsPerDispatch: 128,
|
|
2540
|
+
cadenceDivisor: 1,
|
|
2541
|
+
workgroupScale: 1,
|
|
2542
|
+
maxQueueDepth: 256,
|
|
2543
|
+
},
|
|
2544
|
+
}
|
|
2545
|
+
),
|
|
2546
|
+
suggestedAllocationIds: [
|
|
2547
|
+
"lighting.wavefront.accumulation",
|
|
2548
|
+
"lighting.wavefront.active-queue",
|
|
2549
|
+
],
|
|
2550
|
+
},
|
|
2551
|
+
scatterContinuations: {
|
|
2552
|
+
domain: "lighting",
|
|
2553
|
+
importance: "critical",
|
|
2554
|
+
levels: buildWorkerBudgetLevels(
|
|
2555
|
+
"lighting.wavefront.scatterContinuations",
|
|
2556
|
+
lightingWorkerQueueClass,
|
|
2557
|
+
{
|
|
2558
|
+
low: {
|
|
2559
|
+
estimatedCostMs: 0.8,
|
|
2560
|
+
maxDispatchesPerFrame: 1,
|
|
2561
|
+
maxJobsPerDispatch: 32,
|
|
2562
|
+
cadenceDivisor: 2,
|
|
2563
|
+
workgroupScale: 0.5,
|
|
2564
|
+
maxQueueDepth: 96,
|
|
2565
|
+
},
|
|
2566
|
+
medium: {
|
|
2567
|
+
estimatedCostMs: 1.4,
|
|
2568
|
+
maxDispatchesPerFrame: 1,
|
|
2569
|
+
maxJobsPerDispatch: 64,
|
|
2570
|
+
cadenceDivisor: 1,
|
|
2571
|
+
workgroupScale: 0.75,
|
|
2572
|
+
maxQueueDepth: 192,
|
|
2573
|
+
},
|
|
2574
|
+
high: {
|
|
2575
|
+
estimatedCostMs: 2.1,
|
|
2576
|
+
maxDispatchesPerFrame: 2,
|
|
2577
|
+
maxJobsPerDispatch: 128,
|
|
2578
|
+
cadenceDivisor: 1,
|
|
2579
|
+
workgroupScale: 1,
|
|
2580
|
+
maxQueueDepth: 256,
|
|
2581
|
+
},
|
|
2582
|
+
}
|
|
2583
|
+
),
|
|
2584
|
+
suggestedAllocationIds: [
|
|
2585
|
+
"lighting.wavefront.active-queue",
|
|
2586
|
+
"lighting.wavefront.next-queue",
|
|
2587
|
+
],
|
|
2588
|
+
},
|
|
2589
|
+
},
|
|
2590
|
+
},
|
|
1728
2591
|
volumetrics: {
|
|
1729
2592
|
suggestedAllocationIds: [
|
|
1730
2593
|
"lighting.volumetrics.froxel-grid",
|
|
@@ -1935,6 +2798,13 @@ const lightingWorkerDagSpecs = {
|
|
|
1935
2798
|
accumulate: { priority: 3, dependencies: ["pathTrace"] },
|
|
1936
2799
|
denoise: { priority: 2, dependencies: ["accumulate"] },
|
|
1937
2800
|
},
|
|
2801
|
+
wavefront: {
|
|
2802
|
+
accumulateTerminalRadiance: { priority: 3, dependencies: [] },
|
|
2803
|
+
scatterContinuations: {
|
|
2804
|
+
priority: 2,
|
|
2805
|
+
dependencies: ["accumulateTerminalRadiance"],
|
|
2806
|
+
},
|
|
2807
|
+
},
|
|
1938
2808
|
volumetrics: {
|
|
1939
2809
|
volumetricShadow: { priority: 3, dependencies: [] },
|
|
1940
2810
|
froxelIntegrate: { priority: 2, dependencies: ["volumetricShadow"] },
|
|
@@ -1969,6 +2839,16 @@ function resolveLightingQualityDimensions(techniqueName, jobKey) {
|
|
|
1969
2839
|
"pathtracer.pathTrace": { rayTracing: 1, lightingSamples: 1 },
|
|
1970
2840
|
"pathtracer.accumulate": { temporalReuse: 1, updateCadence: 0.4 },
|
|
1971
2841
|
"pathtracer.denoise": { temporalReuse: 1, shading: 0.4 },
|
|
2842
|
+
"wavefront.accumulateTerminalRadiance": {
|
|
2843
|
+
rayTracing: 1,
|
|
2844
|
+
lightingSamples: 1,
|
|
2845
|
+
temporalReuse: 0.4,
|
|
2846
|
+
},
|
|
2847
|
+
"wavefront.scatterContinuations": {
|
|
2848
|
+
rayTracing: 1,
|
|
2849
|
+
shading: 0.7,
|
|
2850
|
+
updateCadence: 0.5,
|
|
2851
|
+
},
|
|
1972
2852
|
"volumetrics.froxelIntegrate": {
|
|
1973
2853
|
lightingSamples: 0.6,
|
|
1974
2854
|
shading: 0.4,
|
|
@@ -2014,6 +2894,15 @@ function resolveLightingImportanceSignals(techniqueName, jobKey) {
|
|
|
2014
2894
|
},
|
|
2015
2895
|
"pathtracer.accumulate": { visible: true },
|
|
2016
2896
|
"pathtracer.denoise": { visible: true },
|
|
2897
|
+
"wavefront.accumulateTerminalRadiance": {
|
|
2898
|
+
visible: true,
|
|
2899
|
+
shadowSignificance: "high",
|
|
2900
|
+
reflectionSignificance: "high",
|
|
2901
|
+
},
|
|
2902
|
+
"wavefront.scatterContinuations": {
|
|
2903
|
+
visible: true,
|
|
2904
|
+
reflectionSignificance: "high",
|
|
2905
|
+
},
|
|
2017
2906
|
"volumetrics.froxelIntegrate": { visible: true },
|
|
2018
2907
|
"volumetrics.volumetricShadow": { visible: true, shadowSignificance: "high" },
|
|
2019
2908
|
"hdri.irradianceConvolution": { visible: false },
|