@plasius/gpu-lighting 0.2.5 → 0.2.6
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 +14 -3
- package/README.md +37 -0
- package/dist/index.cjs +511 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +499 -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 +229 -0
- package/dist/techniques/techniques/wavefront/scatter-continuations.job.wgsl +136 -0
- package/package.json +2 -1
- package/src/index.js +535 -0
- package/src/techniques/wavefront/accumulate-terminal-radiance.job.wgsl +61 -0
- package/src/techniques/wavefront/prelude.wgsl +229 -0
- package/src/techniques/wavefront/scatter-continuations.job.wgsl +136 -0
package/dist/index.js
CHANGED
|
@@ -41,6 +41,14 @@ var techniqueSpecs = {
|
|
|
41
41
|
denoise: "denoise.job.wgsl"
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
|
+
wavefront: {
|
|
45
|
+
description: "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
|
+
},
|
|
44
52
|
volumetrics: {
|
|
45
53
|
description: "Froxel volumetric lighting for fog, shafts, and participating media shadows.",
|
|
46
54
|
prelude: "prelude.wgsl",
|
|
@@ -1049,6 +1057,374 @@ function createWavefrontEnvironmentLightingOptions(options = {}) {
|
|
|
1049
1057
|
lightingEnvironment: config
|
|
1050
1058
|
});
|
|
1051
1059
|
}
|
|
1060
|
+
var lightingWavefrontSchemaVersion = 1;
|
|
1061
|
+
var lightingWavefrontQueuePairStrategy = "ping-pong-active-next";
|
|
1062
|
+
var lightingWavefrontHitTypes = Object.freeze([
|
|
1063
|
+
"surface",
|
|
1064
|
+
"emissive",
|
|
1065
|
+
"environment",
|
|
1066
|
+
"transparent",
|
|
1067
|
+
"miss"
|
|
1068
|
+
]);
|
|
1069
|
+
var lightingWavefrontTerminalHitTypes = Object.freeze([
|
|
1070
|
+
"emissive",
|
|
1071
|
+
"environment",
|
|
1072
|
+
"miss"
|
|
1073
|
+
]);
|
|
1074
|
+
var lightingWavefrontContinuationHitTypes = Object.freeze([
|
|
1075
|
+
"surface",
|
|
1076
|
+
"transparent"
|
|
1077
|
+
]);
|
|
1078
|
+
var lightingWavefrontPassOrder = Object.freeze([
|
|
1079
|
+
"accumulateTerminalRadiance",
|
|
1080
|
+
"scatterContinuations"
|
|
1081
|
+
]);
|
|
1082
|
+
var lightingRequiredRendererWavefrontPassOrder = Object.freeze([
|
|
1083
|
+
"generatePrimaryRays",
|
|
1084
|
+
"intersectActiveQueue",
|
|
1085
|
+
"resolveSurfaceRecords",
|
|
1086
|
+
"accumulateTerminalRadiance",
|
|
1087
|
+
"scatterContinuations",
|
|
1088
|
+
"compactAndSwapQueues"
|
|
1089
|
+
]);
|
|
1090
|
+
function createLightingWavefrontField(name, type, description) {
|
|
1091
|
+
return Object.freeze({
|
|
1092
|
+
name,
|
|
1093
|
+
type,
|
|
1094
|
+
description
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
function createLightingWavefrontRecordContract(recordName, fields) {
|
|
1098
|
+
return Object.freeze({
|
|
1099
|
+
schemaVersion: lightingWavefrontSchemaVersion,
|
|
1100
|
+
recordName,
|
|
1101
|
+
fields: Object.freeze(fields)
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
var lightingWavefrontBufferContracts = Object.freeze({
|
|
1105
|
+
ray: createLightingWavefrontRecordContract(
|
|
1106
|
+
"RayRecord",
|
|
1107
|
+
[
|
|
1108
|
+
createLightingWavefrontField("rayId", "u32", "Stable ray identifier."),
|
|
1109
|
+
createLightingWavefrontField("parentRayId", "u32", "Parent ray identifier."),
|
|
1110
|
+
createLightingWavefrontField("sourcePixelId", "u32", "Source pixel/sample owner."),
|
|
1111
|
+
createLightingWavefrontField("sampleId", "u32", "Per-pixel sample slot."),
|
|
1112
|
+
createLightingWavefrontField("bounce", "u32", "Current bounce depth."),
|
|
1113
|
+
createLightingWavefrontField("origin", "vec3<f32>", "Ray origin."),
|
|
1114
|
+
createLightingWavefrontField("direction", "vec3<f32>", "Normalized ray direction."),
|
|
1115
|
+
createLightingWavefrontField("throughput", "vec3<f32>", "Accumulated path throughput."),
|
|
1116
|
+
createLightingWavefrontField("mediumRefId", "u32", "Current medium reference."),
|
|
1117
|
+
createLightingWavefrontField("flags", "u32", "Renderer-owned ray flags.")
|
|
1118
|
+
]
|
|
1119
|
+
),
|
|
1120
|
+
hit: createLightingWavefrontRecordContract(
|
|
1121
|
+
"HitRecord",
|
|
1122
|
+
[
|
|
1123
|
+
createLightingWavefrontField("rayId", "u32", "Stable ray identifier."),
|
|
1124
|
+
createLightingWavefrontField("sourcePixelId", "u32", "Source pixel/sample owner."),
|
|
1125
|
+
createLightingWavefrontField("hitType", "u32", "Surface, emissive, environment, transparent, or miss."),
|
|
1126
|
+
createLightingWavefrontField("distance", "f32", "Nearest-hit distance."),
|
|
1127
|
+
createLightingWavefrontField("entityId", "u32", "Owning entity identifier."),
|
|
1128
|
+
createLightingWavefrontField("instanceId", "u32", "Owning instance identifier."),
|
|
1129
|
+
createLightingWavefrontField("primitiveId", "u32", "Primitive identifier."),
|
|
1130
|
+
createLightingWavefrontField("materialId", "u32", "Resolved material identifier."),
|
|
1131
|
+
createLightingWavefrontField("barycentrics", "vec3<f32>", "Triangle barycentrics."),
|
|
1132
|
+
createLightingWavefrontField("uv", "vec2<f32>", "Resolved UV coordinates."),
|
|
1133
|
+
createLightingWavefrontField("geometricNormal", "vec3<f32>", "Geometric surface normal."),
|
|
1134
|
+
createLightingWavefrontField("shadingNormal", "vec3<f32>", "Interpolated shading normal."),
|
|
1135
|
+
createLightingWavefrontField("frontFace", "u32", "Front-face classification.")
|
|
1136
|
+
]
|
|
1137
|
+
),
|
|
1138
|
+
surface: createLightingWavefrontRecordContract(
|
|
1139
|
+
"SurfaceRecord",
|
|
1140
|
+
[
|
|
1141
|
+
createLightingWavefrontField("rayId", "u32", "Stable ray identifier."),
|
|
1142
|
+
createLightingWavefrontField("entityId", "u32", "Owning entity identifier."),
|
|
1143
|
+
createLightingWavefrontField("materialRefId", "u32", "Renderer material reference id."),
|
|
1144
|
+
createLightingWavefrontField("mediumRefId", "u32", "Renderer medium reference id."),
|
|
1145
|
+
createLightingWavefrontField("geometricNormal", "vec3<f32>", "Geometric surface normal."),
|
|
1146
|
+
createLightingWavefrontField("shadingNormal", "vec3<f32>", "Interpolated shading normal."),
|
|
1147
|
+
createLightingWavefrontField("uv", "vec2<f32>", "Resolved UV coordinates."),
|
|
1148
|
+
createLightingWavefrontField("tangentFrame", "mat3x3<f32>", "Resolved tangent frame.")
|
|
1149
|
+
]
|
|
1150
|
+
),
|
|
1151
|
+
materialReference: createLightingWavefrontRecordContract(
|
|
1152
|
+
"MaterialReferenceRecord",
|
|
1153
|
+
[
|
|
1154
|
+
createLightingWavefrontField("materialRefId", "u32", "Lighting-visible material reference id."),
|
|
1155
|
+
createLightingWavefrontField("materialId", "u32", "Source material identifier."),
|
|
1156
|
+
createLightingWavefrontField("shadingModel", "u32", "Renderer shading-model discriminator."),
|
|
1157
|
+
createLightingWavefrontField("textureSetId", "u32", "Resolved texture-set identifier."),
|
|
1158
|
+
createLightingWavefrontField("flags", "u32", "Renderer material flags.")
|
|
1159
|
+
]
|
|
1160
|
+
),
|
|
1161
|
+
mediumReference: createLightingWavefrontRecordContract(
|
|
1162
|
+
"MediumReferenceRecord",
|
|
1163
|
+
[
|
|
1164
|
+
createLightingWavefrontField("mediumRefId", "u32", "Lighting-visible medium reference id."),
|
|
1165
|
+
createLightingWavefrontField("mediumId", "u32", "Source medium identifier."),
|
|
1166
|
+
createLightingWavefrontField("phaseModel", "u32", "Phase-function discriminator."),
|
|
1167
|
+
createLightingWavefrontField("absorption", "vec3<f32>", "Medium absorption coefficients."),
|
|
1168
|
+
createLightingWavefrontField("scattering", "vec3<f32>", "Medium scattering coefficients.")
|
|
1169
|
+
]
|
|
1170
|
+
),
|
|
1171
|
+
accumulation: createLightingWavefrontRecordContract(
|
|
1172
|
+
"AccumulationRecord",
|
|
1173
|
+
[
|
|
1174
|
+
createLightingWavefrontField("sourcePixelId", "u32", "Source pixel/sample owner."),
|
|
1175
|
+
createLightingWavefrontField("sampleCount", "u32", "Accumulated sample count."),
|
|
1176
|
+
createLightingWavefrontField("radiance", "vec3<f32>", "Accumulated radiance."),
|
|
1177
|
+
createLightingWavefrontField("throughput", "vec3<f32>", "Last surviving throughput."),
|
|
1178
|
+
createLightingWavefrontField("resetEpoch", "u32", "Renderer accumulation reset epoch.")
|
|
1179
|
+
]
|
|
1180
|
+
)
|
|
1181
|
+
});
|
|
1182
|
+
var lightingWavefrontTerminationPolicy = Object.freeze({
|
|
1183
|
+
terminalHitTypes: lightingWavefrontTerminalHitTypes,
|
|
1184
|
+
continuationHitTypes: lightingWavefrontContinuationHitTypes,
|
|
1185
|
+
emissive: Object.freeze({
|
|
1186
|
+
action: "accumulate-and-stop",
|
|
1187
|
+
contributesRadiance: true
|
|
1188
|
+
}),
|
|
1189
|
+
environment: Object.freeze({
|
|
1190
|
+
action: "accumulate-and-stop",
|
|
1191
|
+
contributesRadiance: true
|
|
1192
|
+
}),
|
|
1193
|
+
miss: Object.freeze({
|
|
1194
|
+
action: "accumulate-environment-or-dark-stop",
|
|
1195
|
+
contributesRadiance: true
|
|
1196
|
+
})
|
|
1197
|
+
});
|
|
1198
|
+
var defaultWavefrontDarkRadiance = Object.freeze([1e-4, 1e-4, 1e-4]);
|
|
1199
|
+
var wavefrontEventKinds = Object.freeze([
|
|
1200
|
+
"diffuse",
|
|
1201
|
+
"reflection",
|
|
1202
|
+
"refraction",
|
|
1203
|
+
"transparency",
|
|
1204
|
+
"terminate"
|
|
1205
|
+
]);
|
|
1206
|
+
function normalizeWavefrontHitType(value) {
|
|
1207
|
+
return lightingWavefrontHitTypes.includes(value) ? value : "surface";
|
|
1208
|
+
}
|
|
1209
|
+
function normalizeWavefrontEventKind(value) {
|
|
1210
|
+
return wavefrontEventKinds.includes(value) ? value : null;
|
|
1211
|
+
}
|
|
1212
|
+
function normalizeVec3(value, fallback = [0, 0, 0]) {
|
|
1213
|
+
if (!Array.isArray(value) || value.length < 3) {
|
|
1214
|
+
return [...fallback];
|
|
1215
|
+
}
|
|
1216
|
+
return [
|
|
1217
|
+
Number.isFinite(value[0]) ? value[0] : fallback[0],
|
|
1218
|
+
Number.isFinite(value[1]) ? value[1] : fallback[1],
|
|
1219
|
+
Number.isFinite(value[2]) ? value[2] : fallback[2]
|
|
1220
|
+
];
|
|
1221
|
+
}
|
|
1222
|
+
function clampUnit(value, fallback = 0) {
|
|
1223
|
+
return Math.max(0, Math.min(1, readFinite(value, fallback)));
|
|
1224
|
+
}
|
|
1225
|
+
function saturateVec3(value) {
|
|
1226
|
+
return value.map((component) => Math.max(0, component));
|
|
1227
|
+
}
|
|
1228
|
+
function scaleVec3(value, scalar) {
|
|
1229
|
+
return value.map((component) => component * scalar);
|
|
1230
|
+
}
|
|
1231
|
+
function addVec3(left, right) {
|
|
1232
|
+
return left.map((component, index) => component + right[index]);
|
|
1233
|
+
}
|
|
1234
|
+
function multiplyVec3(left, right) {
|
|
1235
|
+
return left.map((component, index) => component * right[index]);
|
|
1236
|
+
}
|
|
1237
|
+
function dotVec3(left, right) {
|
|
1238
|
+
return left[0] * right[0] + left[1] * right[1] + left[2] * right[2];
|
|
1239
|
+
}
|
|
1240
|
+
function lengthVec3(value) {
|
|
1241
|
+
return Math.hypot(value[0], value[1], value[2]);
|
|
1242
|
+
}
|
|
1243
|
+
function normalizeDirection(value, fallback = [0, 1, 0]) {
|
|
1244
|
+
const vector = normalizeVec3(value, fallback);
|
|
1245
|
+
const length = lengthVec3(vector);
|
|
1246
|
+
if (!Number.isFinite(length) || length <= 1e-6) {
|
|
1247
|
+
return [...fallback];
|
|
1248
|
+
}
|
|
1249
|
+
return vector.map((component) => component / length);
|
|
1250
|
+
}
|
|
1251
|
+
function mixVec3(left, right, factor) {
|
|
1252
|
+
return left.map(
|
|
1253
|
+
(component, index) => component * (1 - factor) + right[index] * factor
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
function reflectDirection(direction, normal) {
|
|
1257
|
+
const scale = 2 * dotVec3(direction, normal);
|
|
1258
|
+
return normalizeDirection(
|
|
1259
|
+
[
|
|
1260
|
+
direction[0] - scale * normal[0],
|
|
1261
|
+
direction[1] - scale * normal[1],
|
|
1262
|
+
direction[2] - scale * normal[2]
|
|
1263
|
+
],
|
|
1264
|
+
normal
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
function refractDirection(direction, normal, etaRatio) {
|
|
1268
|
+
const cosTheta = Math.min(-dotVec3(direction, normal), 1);
|
|
1269
|
+
const rOutPerp = scaleVec3(addVec3(direction, scaleVec3(normal, cosTheta)), etaRatio);
|
|
1270
|
+
const rOutPerpLengthSquared = dotVec3(rOutPerp, rOutPerp);
|
|
1271
|
+
const parallelFactor = 1 - rOutPerpLengthSquared;
|
|
1272
|
+
if (parallelFactor <= 0) {
|
|
1273
|
+
return null;
|
|
1274
|
+
}
|
|
1275
|
+
const rOutParallel = scaleVec3(normal, -Math.sqrt(parallelFactor));
|
|
1276
|
+
return normalizeDirection(addVec3(rOutPerp, rOutParallel), direction);
|
|
1277
|
+
}
|
|
1278
|
+
function createWavefrontLightingPlan(options = {}) {
|
|
1279
|
+
const maxDepth = Math.max(1, Math.trunc(readFinite(options.maxDepth, 4)));
|
|
1280
|
+
const queueCapacity = Math.max(
|
|
1281
|
+
1,
|
|
1282
|
+
Math.trunc(readFinite(options.queueCapacity, 4096))
|
|
1283
|
+
);
|
|
1284
|
+
const explicitLightSampling = Boolean(options.explicitLightSampling);
|
|
1285
|
+
const accumulationResetEpoch = Math.max(
|
|
1286
|
+
0,
|
|
1287
|
+
Math.trunc(readFinite(options.accumulationResetEpoch, 0))
|
|
1288
|
+
);
|
|
1289
|
+
return Object.freeze({
|
|
1290
|
+
schemaVersion: lightingWavefrontSchemaVersion,
|
|
1291
|
+
maxDepth,
|
|
1292
|
+
queueCapacity,
|
|
1293
|
+
explicitLightSampling,
|
|
1294
|
+
accumulationResetEpoch,
|
|
1295
|
+
queueLayout: Object.freeze({
|
|
1296
|
+
strategy: lightingWavefrontQueuePairStrategy,
|
|
1297
|
+
compactAfterScatter: true,
|
|
1298
|
+
queues: Object.freeze([
|
|
1299
|
+
Object.freeze({ name: "active", role: "current-bounce" }),
|
|
1300
|
+
Object.freeze({ name: "next", role: "next-bounce" })
|
|
1301
|
+
])
|
|
1302
|
+
}),
|
|
1303
|
+
bufferContracts: lightingWavefrontBufferContracts,
|
|
1304
|
+
terminationPolicy: lightingWavefrontTerminationPolicy,
|
|
1305
|
+
requiredRendererPassOrder: lightingRequiredRendererWavefrontPassOrder,
|
|
1306
|
+
lightingPasses: Object.freeze([
|
|
1307
|
+
Object.freeze({
|
|
1308
|
+
key: "accumulateTerminalRadiance",
|
|
1309
|
+
stage: "accumulateTerminalRadiance",
|
|
1310
|
+
reads: Object.freeze([
|
|
1311
|
+
"ray",
|
|
1312
|
+
"hit",
|
|
1313
|
+
"surface",
|
|
1314
|
+
"materialReference",
|
|
1315
|
+
"mediumReference"
|
|
1316
|
+
]),
|
|
1317
|
+
writes: Object.freeze(["accumulation"]),
|
|
1318
|
+
terminalHitTypes: lightingWavefrontTerminalHitTypes
|
|
1319
|
+
}),
|
|
1320
|
+
Object.freeze({
|
|
1321
|
+
key: "scatterContinuations",
|
|
1322
|
+
stage: "scatterContinuations",
|
|
1323
|
+
reads: Object.freeze([
|
|
1324
|
+
"ray",
|
|
1325
|
+
"hit",
|
|
1326
|
+
"surface",
|
|
1327
|
+
"materialReference",
|
|
1328
|
+
"mediumReference"
|
|
1329
|
+
]),
|
|
1330
|
+
writes: Object.freeze(["ray"]),
|
|
1331
|
+
continuationHitTypes: lightingWavefrontContinuationHitTypes,
|
|
1332
|
+
explicitLightSampling
|
|
1333
|
+
})
|
|
1334
|
+
])
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
function evaluateWavefrontTerminalRadiance(options = {}) {
|
|
1338
|
+
const hitType = normalizeWavefrontHitType(options.hitType);
|
|
1339
|
+
const throughput = saturateVec3(normalizeVec3(options.throughput, [1, 1, 1]));
|
|
1340
|
+
const emission = saturateVec3(normalizeVec3(options.emission, [0, 0, 0]));
|
|
1341
|
+
const environmentRadiance = saturateVec3(
|
|
1342
|
+
normalizeVec3(options.environmentRadiance, [0, 0, 0])
|
|
1343
|
+
);
|
|
1344
|
+
const missRadiance = saturateVec3(
|
|
1345
|
+
normalizeVec3(options.missRadiance, defaultWavefrontDarkRadiance)
|
|
1346
|
+
);
|
|
1347
|
+
const environmentLuminance = colorLuminance(environmentRadiance);
|
|
1348
|
+
let source = "none";
|
|
1349
|
+
let rawRadiance = [0, 0, 0];
|
|
1350
|
+
if (hitType === "emissive") {
|
|
1351
|
+
source = "emissive";
|
|
1352
|
+
rawRadiance = emission;
|
|
1353
|
+
} else if (hitType === "environment") {
|
|
1354
|
+
source = "environment";
|
|
1355
|
+
rawRadiance = environmentRadiance;
|
|
1356
|
+
} else if (hitType === "miss") {
|
|
1357
|
+
source = environmentLuminance > 1e-6 ? "environment" : "dark";
|
|
1358
|
+
rawRadiance = environmentLuminance > 1e-6 ? environmentRadiance : missRadiance;
|
|
1359
|
+
}
|
|
1360
|
+
const radiance = multiplyVec3(throughput, rawRadiance);
|
|
1361
|
+
const terminated = lightingWavefrontTerminalHitTypes.includes(hitType);
|
|
1362
|
+
return Object.freeze({
|
|
1363
|
+
hitType,
|
|
1364
|
+
source,
|
|
1365
|
+
terminated,
|
|
1366
|
+
radiance: Object.freeze(radiance),
|
|
1367
|
+
nearDarkSample: source === "dark" && colorLuminance(radiance) <= colorLuminance(defaultWavefrontDarkRadiance)
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
function evaluateWavefrontContinuationEvent(options = {}) {
|
|
1371
|
+
const hitType = normalizeWavefrontHitType(options.hitType);
|
|
1372
|
+
const bounceIndex = Math.max(0, Math.trunc(readFinite(options.bounceIndex, 0)));
|
|
1373
|
+
const maxDepth = Math.max(1, Math.trunc(readFinite(options.maxDepth, 4)));
|
|
1374
|
+
const throughput = saturateVec3(normalizeVec3(options.throughput, [1, 1, 1]));
|
|
1375
|
+
const albedo = saturateVec3(normalizeVec3(options.albedo, [0.8, 0.8, 0.8]));
|
|
1376
|
+
const transmission = saturateVec3(
|
|
1377
|
+
normalizeVec3(options.transmission, [0, 0, 0])
|
|
1378
|
+
);
|
|
1379
|
+
const shadingNormal = normalizeDirection(options.shadingNormal, [0, 1, 0]);
|
|
1380
|
+
const viewDirection = normalizeDirection(options.viewDirection, [0, 0, 1]);
|
|
1381
|
+
const incomingDirection = normalizeDirection(
|
|
1382
|
+
scaleVec3(viewDirection, -1),
|
|
1383
|
+
[0, 0, -1]
|
|
1384
|
+
);
|
|
1385
|
+
const frontFace = options.frontFace !== false;
|
|
1386
|
+
const orientedNormal = frontFace ? shadingNormal : scaleVec3(shadingNormal, -1);
|
|
1387
|
+
const metalness = clampUnit(options.metalness, 0);
|
|
1388
|
+
const roughness = clampUnit(options.roughness, 0.5);
|
|
1389
|
+
const opacity = clampUnit(options.opacity, 1);
|
|
1390
|
+
const refractiveIndex = Math.max(1, readFinite(options.refractiveIndex ?? options.ior, 1.45));
|
|
1391
|
+
const transmissionStrength = Math.max(...transmission);
|
|
1392
|
+
let eventKind = normalizeWavefrontEventKind(options.eventKind) ?? (hitType === "transparent" || opacity < 0.999 ? "transparency" : transmissionStrength > 1e-3 ? "refraction" : metalness >= 0.5 || roughness <= 0.2 ? "reflection" : "diffuse");
|
|
1393
|
+
let nextDirection = incomingDirection;
|
|
1394
|
+
let attenuation;
|
|
1395
|
+
if (!lightingWavefrontContinuationHitTypes.includes(hitType) || bounceIndex >= maxDepth - 1) {
|
|
1396
|
+
eventKind = "terminate";
|
|
1397
|
+
attenuation = [0, 0, 0];
|
|
1398
|
+
} else if (eventKind === "reflection") {
|
|
1399
|
+
nextDirection = reflectDirection(incomingDirection, orientedNormal);
|
|
1400
|
+
attenuation = mixVec3([0.04, 0.04, 0.04], albedo, metalness);
|
|
1401
|
+
} else if (eventKind === "refraction") {
|
|
1402
|
+
const etaRatio = frontFace ? 1 / refractiveIndex : refractiveIndex;
|
|
1403
|
+
nextDirection = refractDirection(incomingDirection, orientedNormal, etaRatio) ?? reflectDirection(incomingDirection, orientedNormal);
|
|
1404
|
+
attenuation = transmissionStrength > 1e-3 ? transmission : [1, 1, 1];
|
|
1405
|
+
} else if (eventKind === "transparency") {
|
|
1406
|
+
nextDirection = incomingDirection;
|
|
1407
|
+
const transparencyWeight = Math.max(1 - opacity, transmissionStrength, 0.05);
|
|
1408
|
+
attenuation = transmissionStrength > 1e-3 ? transmission : [transparencyWeight, transparencyWeight, transparencyWeight];
|
|
1409
|
+
} else {
|
|
1410
|
+
nextDirection = normalizeDirection(
|
|
1411
|
+
addVec3(orientedNormal, albedo.map((component) => component - 0.5)),
|
|
1412
|
+
orientedNormal
|
|
1413
|
+
);
|
|
1414
|
+
attenuation = scaleVec3(albedo, Math.max(0.05, 1 - metalness));
|
|
1415
|
+
}
|
|
1416
|
+
const nextThroughput = multiplyVec3(throughput, saturateVec3(attenuation));
|
|
1417
|
+
const continueTracing = eventKind !== "terminate" && colorLuminance(nextThroughput) > 1e-4;
|
|
1418
|
+
return Object.freeze({
|
|
1419
|
+
hitType,
|
|
1420
|
+
eventKind,
|
|
1421
|
+
continueTracing,
|
|
1422
|
+
nextDirection: Object.freeze(nextDirection),
|
|
1423
|
+
attenuation: Object.freeze(saturateVec3(attenuation)),
|
|
1424
|
+
nextThroughput: Object.freeze(nextThroughput),
|
|
1425
|
+
explicitLightSamplingEnabled: Boolean(options.explicitLightSampling)
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1052
1428
|
var lightingImportanceLevels = Object.freeze([
|
|
1053
1429
|
"low",
|
|
1054
1430
|
"medium",
|
|
@@ -1614,6 +1990,91 @@ var lightingWorkerSpecPresets = {
|
|
|
1614
1990
|
}
|
|
1615
1991
|
}
|
|
1616
1992
|
},
|
|
1993
|
+
wavefront: {
|
|
1994
|
+
suggestedAllocationIds: [
|
|
1995
|
+
"lighting.wavefront.active-queue",
|
|
1996
|
+
"lighting.wavefront.next-queue",
|
|
1997
|
+
"lighting.wavefront.accumulation"
|
|
1998
|
+
],
|
|
1999
|
+
jobs: {
|
|
2000
|
+
accumulateTerminalRadiance: {
|
|
2001
|
+
domain: "lighting",
|
|
2002
|
+
importance: "critical",
|
|
2003
|
+
levels: buildWorkerBudgetLevels(
|
|
2004
|
+
"lighting.wavefront.accumulateTerminalRadiance",
|
|
2005
|
+
lightingWorkerQueueClass,
|
|
2006
|
+
{
|
|
2007
|
+
low: {
|
|
2008
|
+
estimatedCostMs: 0.7,
|
|
2009
|
+
maxDispatchesPerFrame: 1,
|
|
2010
|
+
maxJobsPerDispatch: 32,
|
|
2011
|
+
cadenceDivisor: 2,
|
|
2012
|
+
workgroupScale: 0.5,
|
|
2013
|
+
maxQueueDepth: 96
|
|
2014
|
+
},
|
|
2015
|
+
medium: {
|
|
2016
|
+
estimatedCostMs: 1.2,
|
|
2017
|
+
maxDispatchesPerFrame: 1,
|
|
2018
|
+
maxJobsPerDispatch: 64,
|
|
2019
|
+
cadenceDivisor: 1,
|
|
2020
|
+
workgroupScale: 0.75,
|
|
2021
|
+
maxQueueDepth: 192
|
|
2022
|
+
},
|
|
2023
|
+
high: {
|
|
2024
|
+
estimatedCostMs: 1.8,
|
|
2025
|
+
maxDispatchesPerFrame: 2,
|
|
2026
|
+
maxJobsPerDispatch: 128,
|
|
2027
|
+
cadenceDivisor: 1,
|
|
2028
|
+
workgroupScale: 1,
|
|
2029
|
+
maxQueueDepth: 256
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
),
|
|
2033
|
+
suggestedAllocationIds: [
|
|
2034
|
+
"lighting.wavefront.accumulation",
|
|
2035
|
+
"lighting.wavefront.active-queue"
|
|
2036
|
+
]
|
|
2037
|
+
},
|
|
2038
|
+
scatterContinuations: {
|
|
2039
|
+
domain: "lighting",
|
|
2040
|
+
importance: "critical",
|
|
2041
|
+
levels: buildWorkerBudgetLevels(
|
|
2042
|
+
"lighting.wavefront.scatterContinuations",
|
|
2043
|
+
lightingWorkerQueueClass,
|
|
2044
|
+
{
|
|
2045
|
+
low: {
|
|
2046
|
+
estimatedCostMs: 0.8,
|
|
2047
|
+
maxDispatchesPerFrame: 1,
|
|
2048
|
+
maxJobsPerDispatch: 32,
|
|
2049
|
+
cadenceDivisor: 2,
|
|
2050
|
+
workgroupScale: 0.5,
|
|
2051
|
+
maxQueueDepth: 96
|
|
2052
|
+
},
|
|
2053
|
+
medium: {
|
|
2054
|
+
estimatedCostMs: 1.4,
|
|
2055
|
+
maxDispatchesPerFrame: 1,
|
|
2056
|
+
maxJobsPerDispatch: 64,
|
|
2057
|
+
cadenceDivisor: 1,
|
|
2058
|
+
workgroupScale: 0.75,
|
|
2059
|
+
maxQueueDepth: 192
|
|
2060
|
+
},
|
|
2061
|
+
high: {
|
|
2062
|
+
estimatedCostMs: 2.1,
|
|
2063
|
+
maxDispatchesPerFrame: 2,
|
|
2064
|
+
maxJobsPerDispatch: 128,
|
|
2065
|
+
cadenceDivisor: 1,
|
|
2066
|
+
workgroupScale: 1,
|
|
2067
|
+
maxQueueDepth: 256
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
),
|
|
2071
|
+
suggestedAllocationIds: [
|
|
2072
|
+
"lighting.wavefront.active-queue",
|
|
2073
|
+
"lighting.wavefront.next-queue"
|
|
2074
|
+
]
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
},
|
|
1617
2078
|
volumetrics: {
|
|
1618
2079
|
suggestedAllocationIds: [
|
|
1619
2080
|
"lighting.volumetrics.froxel-grid",
|
|
@@ -1823,6 +2284,13 @@ var lightingWorkerDagSpecs = {
|
|
|
1823
2284
|
accumulate: { priority: 3, dependencies: ["pathTrace"] },
|
|
1824
2285
|
denoise: { priority: 2, dependencies: ["accumulate"] }
|
|
1825
2286
|
},
|
|
2287
|
+
wavefront: {
|
|
2288
|
+
accumulateTerminalRadiance: { priority: 3, dependencies: [] },
|
|
2289
|
+
scatterContinuations: {
|
|
2290
|
+
priority: 2,
|
|
2291
|
+
dependencies: ["accumulateTerminalRadiance"]
|
|
2292
|
+
}
|
|
2293
|
+
},
|
|
1826
2294
|
volumetrics: {
|
|
1827
2295
|
volumetricShadow: { priority: 3, dependencies: [] },
|
|
1828
2296
|
froxelIntegrate: { priority: 2, dependencies: ["volumetricShadow"] }
|
|
@@ -1856,6 +2324,16 @@ function resolveLightingQualityDimensions(techniqueName, jobKey) {
|
|
|
1856
2324
|
"pathtracer.pathTrace": { rayTracing: 1, lightingSamples: 1 },
|
|
1857
2325
|
"pathtracer.accumulate": { temporalReuse: 1, updateCadence: 0.4 },
|
|
1858
2326
|
"pathtracer.denoise": { temporalReuse: 1, shading: 0.4 },
|
|
2327
|
+
"wavefront.accumulateTerminalRadiance": {
|
|
2328
|
+
rayTracing: 1,
|
|
2329
|
+
lightingSamples: 1,
|
|
2330
|
+
temporalReuse: 0.4
|
|
2331
|
+
},
|
|
2332
|
+
"wavefront.scatterContinuations": {
|
|
2333
|
+
rayTracing: 1,
|
|
2334
|
+
shading: 0.7,
|
|
2335
|
+
updateCadence: 0.5
|
|
2336
|
+
},
|
|
1859
2337
|
"volumetrics.froxelIntegrate": {
|
|
1860
2338
|
lightingSamples: 0.6,
|
|
1861
2339
|
shading: 0.4,
|
|
@@ -1900,6 +2378,15 @@ function resolveLightingImportanceSignals(techniqueName, jobKey) {
|
|
|
1900
2378
|
},
|
|
1901
2379
|
"pathtracer.accumulate": { visible: true },
|
|
1902
2380
|
"pathtracer.denoise": { visible: true },
|
|
2381
|
+
"wavefront.accumulateTerminalRadiance": {
|
|
2382
|
+
visible: true,
|
|
2383
|
+
shadowSignificance: "high",
|
|
2384
|
+
reflectionSignificance: "high"
|
|
2385
|
+
},
|
|
2386
|
+
"wavefront.scatterContinuations": {
|
|
2387
|
+
visible: true,
|
|
2388
|
+
reflectionSignificance: "high"
|
|
2389
|
+
},
|
|
1903
2390
|
"volumetrics.froxelIntegrate": { visible: true },
|
|
1904
2391
|
"volumetrics.volumetricShadow": { visible: true, shadowSignificance: "high" },
|
|
1905
2392
|
"hdri.irradianceConvolution": { visible: false },
|
|
@@ -2169,9 +2656,12 @@ export {
|
|
|
2169
2656
|
createLightingBandPlan,
|
|
2170
2657
|
createLightingProfileModeLadder,
|
|
2171
2658
|
createWavefrontEnvironmentLightingOptions,
|
|
2659
|
+
createWavefrontLightingPlan,
|
|
2172
2660
|
defaultAdaptiveLightingProfilePolicy,
|
|
2173
2661
|
defaultLightingProfile,
|
|
2174
2662
|
defaultLightingTechnique,
|
|
2663
|
+
evaluateWavefrontContinuationEvent,
|
|
2664
|
+
evaluateWavefrontTerminalRadiance,
|
|
2175
2665
|
getLightingProfile,
|
|
2176
2666
|
getLightingProfileWorkerManifest,
|
|
2177
2667
|
getLightingTechnique,
|
|
@@ -2190,8 +2680,17 @@ export {
|
|
|
2190
2680
|
lightingProfileModeOrder,
|
|
2191
2681
|
lightingProfileNames,
|
|
2192
2682
|
lightingProfiles,
|
|
2683
|
+
lightingRequiredRendererWavefrontPassOrder,
|
|
2193
2684
|
lightingTechniqueNames,
|
|
2194
2685
|
lightingTechniques,
|
|
2686
|
+
lightingWavefrontBufferContracts,
|
|
2687
|
+
lightingWavefrontContinuationHitTypes,
|
|
2688
|
+
lightingWavefrontHitTypes,
|
|
2689
|
+
lightingWavefrontPassOrder,
|
|
2690
|
+
lightingWavefrontQueuePairStrategy,
|
|
2691
|
+
lightingWavefrontSchemaVersion,
|
|
2692
|
+
lightingWavefrontTerminalHitTypes,
|
|
2693
|
+
lightingWavefrontTerminationPolicy,
|
|
2195
2694
|
lightingWorkerManifests,
|
|
2196
2695
|
lightingWorkerQueueClass,
|
|
2197
2696
|
loadLightingJobs,
|