@plasius/gpu-lighting 0.1.19 → 0.2.2

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/dist/index.cjs CHANGED
@@ -42,7 +42,12 @@ __export(index_exports, {
42
42
  getLightingTechniqueWorkerManifest: () => getLightingTechniqueWorkerManifest,
43
43
  lightingDebugOwner: () => lightingDebugOwner,
44
44
  lightingDistanceBands: () => lightingDistanceBands,
45
+ lightingEnvironmentLightSourceKinds: () => lightingEnvironmentLightSourceKinds,
46
+ lightingEnvironmentPortalModes: () => lightingEnvironmentPortalModes,
47
+ lightingEnvironmentPortalShapes: () => lightingEnvironmentPortalShapes,
45
48
  lightingEnvironmentPresetNames: () => lightingEnvironmentPresetNames,
49
+ lightingEnvironmentSceneNames: () => lightingEnvironmentSceneNames,
50
+ lightingEnvironmentTimeOfDayNames: () => lightingEnvironmentTimeOfDayNames,
46
51
  lightingJobLabels: () => lightingJobLabels,
47
52
  lightingJobs: () => lightingJobs,
48
53
  lightingPreludeWgslUrl: () => lightingPreludeWgslUrl,
@@ -177,10 +182,45 @@ var lightingProfileModeOrder = Object.freeze([
177
182
  "hybrid",
178
183
  "reference"
179
184
  ]);
180
- var lightingEnvironmentPresetNames = Object.freeze([
181
- "moonlit-harbor",
182
- "product-studio",
183
- "neutral-studio"
185
+ var lightingEnvironmentTimeOfDayNames = Object.freeze([
186
+ "dawn",
187
+ "midday",
188
+ "dusk",
189
+ "night"
190
+ ]);
191
+ var lightingEnvironmentSceneNames = Object.freeze([
192
+ "studio",
193
+ "harbor",
194
+ "grass-field",
195
+ "forest",
196
+ "warehouse",
197
+ "cavern"
198
+ ]);
199
+ var lightingEnvironmentLightSourceKinds = Object.freeze([
200
+ "sky",
201
+ "sun",
202
+ "moon",
203
+ "stars",
204
+ "horizon-glow",
205
+ "ground-bounce",
206
+ "studio-softbox",
207
+ "canopy-transmission",
208
+ "window-portal",
209
+ "fluorescent-strip",
210
+ "sodium-door",
211
+ "emergency-beacon",
212
+ "cave-mouth",
213
+ "torch",
214
+ "bioluminescence",
215
+ "lava-fissure",
216
+ "crystal",
217
+ "custom"
218
+ ]);
219
+ var lightingEnvironmentPortalShapes = Object.freeze(["rectangle"]);
220
+ var lightingEnvironmentPortalModes = Object.freeze([
221
+ "disabled",
222
+ "guide",
223
+ "guide-and-gate"
184
224
  ]);
185
225
  var defaultAdaptiveLightingProfilePolicy = Object.freeze({
186
226
  preferredProfile: "reference",
@@ -195,9 +235,37 @@ var lightingDistanceBands = Object.freeze([
195
235
  ]);
196
236
  var lightingWorkerQueueClass = "lighting";
197
237
  var lightingDebugOwner = "lighting";
238
+ var environmentPresetAmbientScales = Object.freeze({
239
+ "grass-field": 0.78,
240
+ forest: 0.78,
241
+ warehouse: 0.82,
242
+ cavern: 0.78
243
+ });
244
+ var environmentSunlitBaselineByTimeOfDay = Object.freeze({
245
+ dawn: 0.18,
246
+ midday: 0.28,
247
+ dusk: 0.14,
248
+ night: 0.035
249
+ });
250
+ var environmentSunlitBaselineSceneScales = Object.freeze({
251
+ "grass-field": 1,
252
+ forest: 0.78,
253
+ warehouse: 0.62,
254
+ cavern: 0.42,
255
+ harbor: 0.85,
256
+ studio: 0.58
257
+ });
198
258
  function freezeVec4(value) {
199
259
  return Object.freeze([value[0], value[1], value[2], value[3] ?? 1]);
200
260
  }
261
+ function scaleVec4(value, scale) {
262
+ return [
263
+ value[0] * scale,
264
+ value[1] * scale,
265
+ value[2] * scale,
266
+ value[3] ?? 1
267
+ ];
268
+ }
201
269
  function normalizeVector3(value, fallback) {
202
270
  if (!Array.isArray(value) || value.length < 3) {
203
271
  return [...fallback];
@@ -224,12 +292,290 @@ function readColor(value, fallback) {
224
292
  Number.isFinite(value[3]) ? Math.max(0, Math.min(1, value[3])) : fallback[3] ?? 1
225
293
  ]);
226
294
  }
295
+ function colorLuminance(value) {
296
+ return value[0] * 0.2126 + value[1] * 0.7152 + value[2] * 0.0722;
297
+ }
298
+ function readPositiveColor(value, fallback) {
299
+ const color = readColor(value, fallback);
300
+ const fallbackColor = readColor(fallback, [1, 1, 1, 1]);
301
+ return freezeVec4([
302
+ color[0] > 0 ? color[0] : Math.max(fallbackColor[0], 1e-4),
303
+ color[1] > 0 ? color[1] : Math.max(fallbackColor[1], 1e-4),
304
+ color[2] > 0 ? color[2] : Math.max(fallbackColor[2], 1e-4),
305
+ color[3]
306
+ ]);
307
+ }
308
+ function ensureNonNullColor(value, fallback = [1, 1, 1, 1]) {
309
+ const color = readColor(value, fallback);
310
+ if (colorLuminance(color) > 1e-6) {
311
+ return color;
312
+ }
313
+ return readPositiveColor(fallback, [1, 1, 1, 1]);
314
+ }
227
315
  function readFinite(value, fallback) {
228
316
  return Number.isFinite(value) ? value : fallback;
229
317
  }
318
+ function readVector3(value, fallback) {
319
+ if (!Array.isArray(value) || value.length < 3) {
320
+ return [...fallback];
321
+ }
322
+ return [
323
+ Number.isFinite(value[0]) ? value[0] : fallback[0],
324
+ Number.isFinite(value[1]) ? value[1] : fallback[1],
325
+ Number.isFinite(value[2]) ? value[2] : fallback[2]
326
+ ];
327
+ }
328
+ function dot3(a, b) {
329
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
330
+ }
331
+ function cross3(a, b) {
332
+ return [
333
+ a[1] * b[2] - a[2] * b[1],
334
+ a[2] * b[0] - a[0] * b[2],
335
+ a[0] * b[1] - a[1] * b[0]
336
+ ];
337
+ }
338
+ function normalizeRawVector3(value, fallback) {
339
+ const length = Math.hypot(value[0], value[1], value[2]);
340
+ if (!Number.isFinite(length) || length <= 1e-6) {
341
+ return [...fallback];
342
+ }
343
+ return value.map((component) => component / length);
344
+ }
345
+ function orthogonalFallback(normal) {
346
+ if (Math.abs(normal[1]) < 0.92) {
347
+ return normalizeRawVector3(cross3([0, 1, 0], normal), [1, 0, 0]);
348
+ }
349
+ return normalizeRawVector3(cross3([1, 0, 0], normal), [0, 0, 1]);
350
+ }
351
+ function normalizePortalTangent(value, normal) {
352
+ const raw = normalizeVector3(value, orthogonalFallback(normal));
353
+ const projected = [
354
+ raw[0] - normal[0] * dot3(raw, normal),
355
+ raw[1] - normal[1] * dot3(raw, normal),
356
+ raw[2] - normal[2] * dot3(raw, normal)
357
+ ];
358
+ return normalizeRawVector3(projected, orthogonalFallback(normal));
359
+ }
360
+ function readPositiveFinite(value, fallback) {
361
+ const number = Number(value ?? fallback);
362
+ if (!Number.isFinite(number)) {
363
+ return fallback;
364
+ }
365
+ return Math.max(number, 1e-4);
366
+ }
367
+ function normalizeEnvironmentPortalMode(value, hasPortals) {
368
+ if (value == null) {
369
+ return hasPortals ? "guide-and-gate" : "disabled";
370
+ }
371
+ if (value === "gate") {
372
+ return "guide-and-gate";
373
+ }
374
+ if (lightingEnvironmentPortalModes.includes(value)) {
375
+ return value;
376
+ }
377
+ throw new Error(
378
+ `environmentPortalMode must be one of: ${lightingEnvironmentPortalModes.join(", ")}.`
379
+ );
380
+ }
381
+ function normalizeEnvironmentPortal(portal, index) {
382
+ if (!portal || typeof portal !== "object") {
383
+ throw new Error(`environmentPortals[${index}] must be an object.`);
384
+ }
385
+ const shape = portal.shape ?? portal.kind ?? "rectangle";
386
+ if (!lightingEnvironmentPortalShapes.includes(shape)) {
387
+ throw new Error(
388
+ `environmentPortals[${index}].shape must be one of: ${lightingEnvironmentPortalShapes.join(", ")}.`
389
+ );
390
+ }
391
+ const normal = Object.freeze(
392
+ normalizeVector3(portal.normal, [0, 0, 1])
393
+ );
394
+ const tangent = Object.freeze(normalizePortalTangent(portal.tangent, normal));
395
+ const bitangent = Object.freeze(
396
+ normalizeRawVector3(cross3(normal, tangent), [0, 1, 0])
397
+ );
398
+ const width = readPositiveFinite(
399
+ portal.width,
400
+ readPositiveFinite(portal.halfWidth, 0.5) * 2
401
+ );
402
+ const height = readPositiveFinite(
403
+ portal.height,
404
+ readPositiveFinite(portal.halfHeight, 0.5) * 2
405
+ );
406
+ const radianceScale = Math.max(
407
+ 0,
408
+ readFinite(portal.radianceScale ?? portal.intensity, 1)
409
+ );
410
+ return Object.freeze({
411
+ id: typeof portal.id === "string" && portal.id.length > 0 ? portal.id : `environment-portal-${index}`,
412
+ shape,
413
+ position: Object.freeze(readVector3(portal.position ?? portal.center, [0, 0, 0])),
414
+ normal,
415
+ tangent,
416
+ bitangent,
417
+ width,
418
+ height,
419
+ radianceScale,
420
+ color: readColor(portal.color, [1, 1, 1, 1]),
421
+ twoSided: portal.twoSided !== false
422
+ });
423
+ }
424
+ function normalizeEnvironmentPortals(value) {
425
+ if (value == null) {
426
+ return Object.freeze([]);
427
+ }
428
+ if (!Array.isArray(value)) {
429
+ throw new Error("environmentPortals must be an array when provided.");
430
+ }
431
+ return Object.freeze(value.map(normalizeEnvironmentPortal));
432
+ }
433
+ function normalizeEnvironmentMap(value) {
434
+ if (value == null) {
435
+ return null;
436
+ }
437
+ if (!value || typeof value !== "object") {
438
+ throw new Error("environmentMap must be an object when provided.");
439
+ }
440
+ return Object.freeze({
441
+ ...value,
442
+ id: typeof value.id === "string" && value.id.length > 0 ? value.id : "environment-map",
443
+ projection: typeof value.projection === "string" && value.projection.length > 0 ? value.projection : "equirectangular",
444
+ intensity: readPositiveFinite(value.intensity ?? value.radianceScale, 1),
445
+ rotationRadians: readFinite(value.rotationRadians ?? value.rotation, 0),
446
+ ambientStrength: Math.max(0, readFinite(value.ambientStrength, 0.32))
447
+ });
448
+ }
449
+ function freezeLightSourceSpec(source) {
450
+ return Object.freeze({
451
+ ...source,
452
+ color: source.color ? freezeVec4(source.color) : void 0,
453
+ direction: source.direction ? Object.freeze(normalizeVector3(source.direction, [0, 1, 0])) : void 0,
454
+ position: source.position ? Object.freeze(readVector3(source.position, [0, 0, 0])) : void 0
455
+ });
456
+ }
457
+ function defineEnvironmentPreset(spec) {
458
+ const scene = spec.scene ?? "studio";
459
+ const timeOfDay = spec.timeOfDay ?? "midday";
460
+ const ambientScale = Math.max(
461
+ 0,
462
+ readFinite(spec.ambientScale, environmentPresetAmbientScales[scene] ?? 1)
463
+ );
464
+ const defaultSunlitBaseline = (environmentSunlitBaselineByTimeOfDay[timeOfDay] ?? environmentSunlitBaselineByTimeOfDay.midday) * (environmentSunlitBaselineSceneScales[scene] ?? 0.58);
465
+ const sunlitBaseline = Math.max(
466
+ 0,
467
+ readFinite(spec.sunlitBaseline, defaultSunlitBaseline)
468
+ );
469
+ return Object.freeze({
470
+ ...spec,
471
+ scene,
472
+ timeOfDay,
473
+ horizonColor: freezeVec4(spec.horizonColor),
474
+ zenithColor: freezeVec4(spec.zenithColor),
475
+ sunDirection: Object.freeze(normalizeVector3(spec.sunDirection, [0, 1, 0])),
476
+ sunColor: freezeVec4(spec.sunColor),
477
+ ambientColor: freezeVec4(scaleVec4(spec.ambientColor, ambientScale)),
478
+ sunlitBaseline,
479
+ environmentLightSources: Object.freeze(
480
+ (spec.environmentLightSources ?? []).map(freezeLightSourceSpec)
481
+ )
482
+ });
483
+ }
484
+ function buildEnvironmentLightSourceFallback(config, preset) {
485
+ const firstPresetSource = preset.environmentLightSources[0] ?? {};
486
+ return {
487
+ kind: firstPresetSource.kind ?? "sky",
488
+ role: firstPresetSource.role ?? "fill",
489
+ color: firstPresetSource.color ?? config.sunColor,
490
+ intensity: firstPresetSource.intensity ?? Math.max(config.environmentIntensity, 1e-4),
491
+ direction: firstPresetSource.direction ?? config.sunDirection,
492
+ angularRadiusRadians: firstPresetSource.angularRadiusRadians ?? 0.25,
493
+ reach: firstPresetSource.reach ?? 1e3
494
+ };
495
+ }
496
+ function normalizeEnvironmentLightSource(source, index, fallback) {
497
+ if (!source || typeof source !== "object") {
498
+ throw new Error(`environmentLightSources[${index}] must be an object.`);
499
+ }
500
+ const requestedKind = source.kind ?? source.type ?? fallback.kind ?? "custom";
501
+ const kind = lightingEnvironmentLightSourceKinds.includes(requestedKind) ? requestedKind : "custom";
502
+ const color = readPositiveColor(source.color, fallback.color ?? [1, 1, 1, 1]);
503
+ const intensity = readPositiveFinite(
504
+ source.intensity ?? source.radianceScale,
505
+ fallback.intensity ?? 1
506
+ );
507
+ const radiance = freezeVec4([
508
+ color[0] * intensity,
509
+ color[1] * intensity,
510
+ color[2] * intensity,
511
+ color[3]
512
+ ]);
513
+ return Object.freeze({
514
+ id: typeof source.id === "string" && source.id.length > 0 ? source.id : `environment-light-source-${index}`,
515
+ kind,
516
+ type: kind,
517
+ role: typeof source.role === "string" && source.role.length > 0 ? source.role : fallback.role ?? "fill",
518
+ direction: Object.freeze(
519
+ normalizeVector3(source.direction, fallback.direction ?? [0, 1, 0])
520
+ ),
521
+ position: Object.freeze(
522
+ readVector3(source.position ?? source.origin, fallback.position ?? [0, 0, 0])
523
+ ),
524
+ color,
525
+ intensity,
526
+ radiance,
527
+ luminance: colorLuminance(radiance),
528
+ angularRadiusRadians: readPositiveFinite(
529
+ source.angularRadiusRadians ?? source.angularRadius,
530
+ fallback.angularRadiusRadians ?? 0.25
531
+ ),
532
+ reach: readPositiveFinite(
533
+ source.reach ?? source.distance,
534
+ fallback.reach ?? 1e3
535
+ ),
536
+ castsShadows: source.castsShadows !== false,
537
+ contributesToEnvironment: source.contributesToEnvironment !== false
538
+ });
539
+ }
540
+ function normalizeEnvironmentLightSources(value, preset, config) {
541
+ const baseSources = value ?? preset.environmentLightSources;
542
+ const fallback = buildEnvironmentLightSourceFallback(config, preset);
543
+ if (!Array.isArray(baseSources)) {
544
+ throw new Error("environmentLightSources must be an array when provided.");
545
+ }
546
+ const normalizedSources = baseSources.length > 0 ? baseSources.map(
547
+ (source, index) => normalizeEnvironmentLightSource(source, index, fallback)
548
+ ) : [normalizeEnvironmentLightSource(fallback, 0, fallback)];
549
+ return Object.freeze(normalizedSources);
550
+ }
551
+ function findDominantEnvironmentLightSource(sources) {
552
+ return sources.reduce(
553
+ (dominant, source) => source.luminance > dominant.luminance ? source : dominant
554
+ );
555
+ }
556
+ function createEnvironmentMissLighting(source, environmentColor) {
557
+ const fallbackRadiance = readPositiveColor(environmentColor, source.radiance);
558
+ const radiance = ensureNonNullColor(source.radiance, fallbackRadiance);
559
+ const color = readPositiveColor(source.color, environmentColor);
560
+ return Object.freeze({
561
+ sourceId: source.id,
562
+ kind: source.kind,
563
+ role: source.role,
564
+ contribution: "inferred-environment",
565
+ startingPoint: "environment-miss",
566
+ direction: source.direction,
567
+ position: source.position,
568
+ color,
569
+ intensity: Math.max(source.intensity, 1e-4),
570
+ radiance,
571
+ luminance: Math.max(colorLuminance(radiance), 1e-4)
572
+ });
573
+ }
230
574
  var environmentLightingPresets = Object.freeze({
231
- "moonlit-harbor": Object.freeze({
575
+ "moonlit-harbor": defineEnvironmentPreset({
232
576
  preset: "moonlit-harbor",
577
+ scene: "harbor",
578
+ timeOfDay: "night",
233
579
  environmentMode: 0,
234
580
  environmentIntensity: 0.86,
235
581
  exposure: 1,
@@ -237,10 +583,31 @@ var environmentLightingPresets = Object.freeze({
237
583
  zenithColor: freezeVec4([0.035, 0.07, 0.14, 1]),
238
584
  sunDirection: Object.freeze(normalizeVector3([0.22, 0.88, 0.42], [0, 1, 0])),
239
585
  sunColor: freezeVec4([2.1, 2.25, 2.65, 1]),
240
- ambientColor: freezeVec4([0.018, 0.023, 0.03, 1])
586
+ ambientColor: freezeVec4([0.018, 0.023, 0.03, 1]),
587
+ environmentLightSources: [
588
+ {
589
+ id: "harbor-moon",
590
+ kind: "moon",
591
+ role: "key",
592
+ direction: [0.22, 0.88, 0.42],
593
+ color: [0.7, 0.76, 0.9, 1],
594
+ intensity: 2.2,
595
+ angularRadiusRadians: 0.018
596
+ },
597
+ {
598
+ id: "harbor-sky",
599
+ kind: "sky",
600
+ role: "fill",
601
+ direction: [0, 1, 0],
602
+ color: [0.22, 0.31, 0.48, 1],
603
+ intensity: 0.35
604
+ }
605
+ ]
241
606
  }),
242
- "product-studio": Object.freeze({
607
+ "product-studio": defineEnvironmentPreset({
243
608
  preset: "product-studio",
609
+ scene: "studio",
610
+ timeOfDay: "midday",
244
611
  environmentMode: 1,
245
612
  environmentIntensity: 1.05,
246
613
  exposure: 1,
@@ -248,10 +615,32 @@ var environmentLightingPresets = Object.freeze({
248
615
  zenithColor: freezeVec4([0.18, 0.22, 0.26, 1]),
249
616
  sunDirection: Object.freeze(normalizeVector3([0.18, 0.93, 0.24], [0, 1, 0])),
250
617
  sunColor: freezeVec4([3.8, 3.55, 2.85, 1]),
251
- ambientColor: freezeVec4([0.024, 0.027, 0.03, 1])
618
+ ambientColor: freezeVec4([0.024, 0.027, 0.03, 1]),
619
+ environmentLightSources: [
620
+ {
621
+ id: "studio-key-softbox",
622
+ kind: "studio-softbox",
623
+ role: "key",
624
+ direction: [0.18, 0.93, 0.24],
625
+ color: [1, 0.94, 0.82, 1],
626
+ intensity: 4.1,
627
+ angularRadiusRadians: 0.42
628
+ },
629
+ {
630
+ id: "studio-fill-panel",
631
+ kind: "studio-softbox",
632
+ role: "fill",
633
+ direction: [-0.56, 0.62, -0.2],
634
+ color: [0.75, 0.84, 1, 1],
635
+ intensity: 1.3,
636
+ angularRadiusRadians: 0.55
637
+ }
638
+ ]
252
639
  }),
253
- "neutral-studio": Object.freeze({
640
+ "neutral-studio": defineEnvironmentPreset({
254
641
  preset: "neutral-studio",
642
+ scene: "studio",
643
+ timeOfDay: "midday",
255
644
  environmentMode: 2,
256
645
  environmentIntensity: 0.95,
257
646
  exposure: 1,
@@ -259,13 +648,335 @@ var environmentLightingPresets = Object.freeze({
259
648
  zenithColor: freezeVec4([0.24, 0.26, 0.29, 1]),
260
649
  sunDirection: Object.freeze(normalizeVector3([-0.24, 0.86, 0.36], [0, 1, 0])),
261
650
  sunColor: freezeVec4([2.4, 2.35, 2.2, 1]),
262
- ambientColor: freezeVec4([0.028, 0.029, 0.03, 1])
651
+ ambientColor: freezeVec4([0.028, 0.029, 0.03, 1]),
652
+ environmentLightSources: [
653
+ {
654
+ id: "neutral-studio-overhead",
655
+ kind: "studio-softbox",
656
+ role: "key",
657
+ direction: [-0.24, 0.86, 0.36],
658
+ color: [0.96, 0.97, 1, 1],
659
+ intensity: 2.5,
660
+ angularRadiusRadians: 0.5
661
+ },
662
+ {
663
+ id: "neutral-studio-wall-bounce",
664
+ kind: "ground-bounce",
665
+ role: "fill",
666
+ direction: [0.2, 0.3, -0.9],
667
+ color: [0.55, 0.58, 0.62, 1],
668
+ intensity: 0.8
669
+ }
670
+ ]
671
+ }),
672
+ "grass-field-dawn": defineEnvironmentPreset({
673
+ preset: "grass-field-dawn",
674
+ scene: "grass-field",
675
+ timeOfDay: "dawn",
676
+ environmentMode: 3,
677
+ environmentIntensity: 0.92,
678
+ exposure: 1.06,
679
+ horizonColor: [0.92, 0.54, 0.32, 1],
680
+ zenithColor: [0.16, 0.28, 0.5, 1],
681
+ sunDirection: [0.64, 0.32, 0.18],
682
+ sunColor: [5.6, 3.15, 1.55, 1],
683
+ ambientColor: [0.034, 0.047, 0.032, 1],
684
+ environmentLightSources: [
685
+ { id: "field-dawn-sun", kind: "sun", role: "key", direction: [0.64, 0.32, 0.18], color: [1, 0.58, 0.28, 1], intensity: 5.6, angularRadiusRadians: 0.012 },
686
+ { id: "field-dawn-sky", kind: "sky", role: "fill", direction: [0, 1, 0], color: [0.36, 0.52, 0.82, 1], intensity: 0.9 },
687
+ { id: "field-dawn-grass-bounce", kind: "ground-bounce", role: "bounce", direction: [0, 0.25, 0.1], color: [0.22, 0.44, 0.12, 1], intensity: 0.45 }
688
+ ]
689
+ }),
690
+ "grass-field-midday": defineEnvironmentPreset({
691
+ preset: "grass-field-midday",
692
+ scene: "grass-field",
693
+ timeOfDay: "midday",
694
+ environmentMode: 4,
695
+ environmentIntensity: 1.18,
696
+ exposure: 0.96,
697
+ horizonColor: [0.58, 0.78, 0.96, 1],
698
+ zenithColor: [0.1, 0.34, 0.82, 1],
699
+ sunDirection: [0.18, 0.98, 0.08],
700
+ sunColor: [9.8, 9.4, 8.55, 1],
701
+ ambientColor: [0.048, 0.062, 0.04, 1],
702
+ environmentLightSources: [
703
+ { id: "field-midday-sun", kind: "sun", role: "key", direction: [0.18, 0.98, 0.08], color: [1, 0.96, 0.86, 1], intensity: 9.8, angularRadiusRadians: 93e-4 },
704
+ { id: "field-midday-sky", kind: "sky", role: "fill", direction: [0, 1, 0], color: [0.48, 0.7, 1, 1], intensity: 1.8 },
705
+ { id: "field-midday-ground", kind: "ground-bounce", role: "bounce", direction: [0, 0.35, -0.15], color: [0.28, 0.56, 0.16, 1], intensity: 0.65 }
706
+ ]
707
+ }),
708
+ "grass-field-dusk": defineEnvironmentPreset({
709
+ preset: "grass-field-dusk",
710
+ scene: "grass-field",
711
+ timeOfDay: "dusk",
712
+ environmentMode: 5,
713
+ environmentIntensity: 0.82,
714
+ exposure: 1.12,
715
+ horizonColor: [1.08, 0.42, 0.24, 1],
716
+ zenithColor: [0.09, 0.1, 0.32, 1],
717
+ sunDirection: [-0.76, 0.24, 0.22],
718
+ sunColor: [4.8, 1.65, 0.72, 1],
719
+ ambientColor: [0.026, 0.026, 0.034, 1],
720
+ environmentLightSources: [
721
+ { id: "field-dusk-sun", kind: "sun", role: "key", direction: [-0.76, 0.24, 0.22], color: [1, 0.34, 0.16, 1], intensity: 4.8, angularRadiusRadians: 0.014 },
722
+ { id: "field-dusk-horizon", kind: "horizon-glow", role: "fill", direction: [-0.9, 0.08, 0.1], color: [0.92, 0.28, 0.16, 1], intensity: 1.2 },
723
+ { id: "field-dusk-grass", kind: "ground-bounce", role: "bounce", direction: [0, 0.22, 0.2], color: [0.12, 0.28, 0.11, 1], intensity: 0.35 }
724
+ ]
725
+ }),
726
+ "grass-field-night": defineEnvironmentPreset({
727
+ preset: "grass-field-night",
728
+ scene: "grass-field",
729
+ timeOfDay: "night",
730
+ environmentMode: 6,
731
+ environmentIntensity: 0.48,
732
+ exposure: 1.35,
733
+ horizonColor: [0.08, 0.13, 0.2, 1],
734
+ zenithColor: [0.018, 0.035, 0.09, 1],
735
+ sunDirection: [-0.22, 0.86, -0.34],
736
+ sunColor: [0.72, 0.82, 1.35, 1],
737
+ ambientColor: [0.012, 0.017, 0.026, 1],
738
+ environmentLightSources: [
739
+ { id: "field-night-moon", kind: "moon", role: "key", direction: [-0.22, 0.86, -0.34], color: [0.52, 0.62, 1, 1], intensity: 1.25, angularRadiusRadians: 0.018 },
740
+ { id: "field-night-stars", kind: "stars", role: "fill", direction: [0, 1, 0], color: [0.32, 0.38, 0.6, 1], intensity: 0.24 },
741
+ { id: "field-night-horizon", kind: "horizon-glow", role: "rim", direction: [0.8, 0.08, -0.15], color: [0.08, 0.14, 0.26, 1], intensity: 0.28 }
742
+ ]
743
+ }),
744
+ "forest-dawn": defineEnvironmentPreset({
745
+ preset: "forest-dawn",
746
+ scene: "forest",
747
+ timeOfDay: "dawn",
748
+ environmentMode: 7,
749
+ environmentIntensity: 0.78,
750
+ exposure: 1.14,
751
+ horizonColor: [0.72, 0.48, 0.28, 1],
752
+ zenithColor: [0.08, 0.18, 0.18, 1],
753
+ sunDirection: [0.58, 0.42, -0.24],
754
+ sunColor: [4.4, 2.65, 1.32, 1],
755
+ ambientColor: [0.024, 0.04, 0.026, 1],
756
+ environmentLightSources: [
757
+ { id: "forest-dawn-sun-shaft", kind: "sun", role: "key", direction: [0.58, 0.42, -0.24], color: [1, 0.62, 0.32, 1], intensity: 4.4, angularRadiusRadians: 0.018 },
758
+ { id: "forest-dawn-canopy", kind: "canopy-transmission", role: "filter", direction: [0.12, 0.78, 0.2], color: [0.34, 0.68, 0.24, 1], intensity: 0.86 },
759
+ { id: "forest-dawn-sky-gap", kind: "sky", role: "fill", direction: [-0.18, 0.92, 0.12], color: [0.28, 0.46, 0.62, 1], intensity: 0.48 }
760
+ ]
761
+ }),
762
+ "forest-midday": defineEnvironmentPreset({
763
+ preset: "forest-midday",
764
+ scene: "forest",
765
+ timeOfDay: "midday",
766
+ environmentMode: 8,
767
+ environmentIntensity: 0.96,
768
+ exposure: 1.02,
769
+ horizonColor: [0.38, 0.62, 0.42, 1],
770
+ zenithColor: [0.08, 0.28, 0.32, 1],
771
+ sunDirection: [0.08, 0.96, -0.18],
772
+ sunColor: [7.2, 6.9, 5.25, 1],
773
+ ambientColor: [0.034, 0.055, 0.032, 1],
774
+ environmentLightSources: [
775
+ { id: "forest-midday-sun-gap", kind: "sun", role: "key", direction: [0.08, 0.96, -0.18], color: [1, 0.96, 0.74, 1], intensity: 7.2, angularRadiusRadians: 0.013 },
776
+ { id: "forest-midday-leaves", kind: "canopy-transmission", role: "filter", direction: [0.32, 0.75, 0.12], color: [0.24, 0.72, 0.28, 1], intensity: 1.35 },
777
+ { id: "forest-midday-floor", kind: "ground-bounce", role: "bounce", direction: [-0.1, 0.25, 0.18], color: [0.18, 0.35, 0.13, 1], intensity: 0.42 }
778
+ ]
779
+ }),
780
+ "forest-dusk": defineEnvironmentPreset({
781
+ preset: "forest-dusk",
782
+ scene: "forest",
783
+ timeOfDay: "dusk",
784
+ environmentMode: 9,
785
+ environmentIntensity: 0.68,
786
+ exposure: 1.2,
787
+ horizonColor: [0.72, 0.28, 0.2, 1],
788
+ zenithColor: [0.04, 0.07, 0.18, 1],
789
+ sunDirection: [-0.7, 0.28, -0.18],
790
+ sunColor: [3.2, 1.18, 0.56, 1],
791
+ ambientColor: [0.018, 0.026, 0.024, 1],
792
+ environmentLightSources: [
793
+ { id: "forest-dusk-horizon", kind: "horizon-glow", role: "key", direction: [-0.7, 0.18, -0.18], color: [1, 0.34, 0.2, 1], intensity: 2.2, angularRadiusRadians: 0.1 },
794
+ { id: "forest-dusk-canopy", kind: "canopy-transmission", role: "filter", direction: [0.18, 0.7, 0.26], color: [0.18, 0.38, 0.2, 1], intensity: 0.52 },
795
+ { id: "forest-dusk-sky-gap", kind: "sky", role: "fill", direction: [0, 1, 0], color: [0.12, 0.16, 0.34, 1], intensity: 0.42 }
796
+ ]
797
+ }),
798
+ "forest-night": defineEnvironmentPreset({
799
+ preset: "forest-night",
800
+ scene: "forest",
801
+ timeOfDay: "night",
802
+ environmentMode: 10,
803
+ environmentIntensity: 0.42,
804
+ exposure: 1.42,
805
+ horizonColor: [0.035, 0.08, 0.1, 1],
806
+ zenithColor: [0.012, 0.025, 0.06, 1],
807
+ sunDirection: [0.2, 0.82, -0.46],
808
+ sunColor: [0.42, 0.56, 1.1, 1],
809
+ ambientColor: [0.01, 0.016, 0.02, 1],
810
+ environmentLightSources: [
811
+ { id: "forest-night-moon-gap", kind: "moon", role: "key", direction: [0.2, 0.82, -0.46], color: [0.42, 0.56, 1, 1], intensity: 0.95, angularRadiusRadians: 0.025 },
812
+ { id: "forest-night-canopy", kind: "canopy-transmission", role: "filter", direction: [-0.16, 0.66, 0.1], color: [0.08, 0.18, 0.12, 1], intensity: 0.28 },
813
+ { id: "forest-night-stars", kind: "stars", role: "fill", direction: [0, 1, 0], color: [0.22, 0.28, 0.5, 1], intensity: 0.18 }
814
+ ]
815
+ }),
816
+ "warehouse-dawn": defineEnvironmentPreset({
817
+ preset: "warehouse-dawn",
818
+ scene: "warehouse",
819
+ timeOfDay: "dawn",
820
+ environmentMode: 11,
821
+ environmentIntensity: 0.74,
822
+ exposure: 1.08,
823
+ horizonColor: [0.58, 0.44, 0.34, 1],
824
+ zenithColor: [0.16, 0.19, 0.24, 1],
825
+ sunDirection: [0.82, 0.28, 0.18],
826
+ sunColor: [2.8, 1.7, 0.92, 1],
827
+ ambientColor: [0.028, 0.03, 0.032, 1],
828
+ environmentLightSources: [
829
+ { id: "warehouse-dawn-loading-door", kind: "window-portal", role: "key", direction: [0.82, 0.28, 0.18], color: [1, 0.62, 0.34, 1], intensity: 2.8, angularRadiusRadians: 0.22 },
830
+ { id: "warehouse-dawn-fluorescent", kind: "fluorescent-strip", role: "fill", direction: [0, 1, 0], color: [0.78, 0.9, 1, 1], intensity: 1.1, angularRadiusRadians: 0.35 },
831
+ { id: "warehouse-dawn-concrete-bounce", kind: "ground-bounce", role: "bounce", direction: [0, 0.28, -0.2], color: [0.34, 0.36, 0.38, 1], intensity: 0.42 }
832
+ ]
833
+ }),
834
+ "warehouse-midday": defineEnvironmentPreset({
835
+ preset: "warehouse-midday",
836
+ scene: "warehouse",
837
+ timeOfDay: "midday",
838
+ environmentMode: 12,
839
+ environmentIntensity: 0.92,
840
+ exposure: 0.98,
841
+ horizonColor: [0.64, 0.7, 0.74, 1],
842
+ zenithColor: [0.28, 0.34, 0.42, 1],
843
+ sunDirection: [0.35, 0.86, 0.16],
844
+ sunColor: [4.2, 4, 3.45, 1],
845
+ ambientColor: [0.034, 0.036, 0.038, 1],
846
+ environmentLightSources: [
847
+ { id: "warehouse-midday-skylights", kind: "window-portal", role: "key", direction: [0.35, 0.86, 0.16], color: [0.92, 0.96, 1, 1], intensity: 4.2, angularRadiusRadians: 0.18 },
848
+ { id: "warehouse-midday-fluorescent", kind: "fluorescent-strip", role: "fill", direction: [-0.2, 0.92, 0.1], color: [0.78, 0.92, 1, 1], intensity: 1.6, angularRadiusRadians: 0.45 },
849
+ { id: "warehouse-midday-door-spill", kind: "sodium-door", role: "rim", direction: [-0.82, 0.18, -0.12], color: [1, 0.58, 0.24, 1], intensity: 0.68 }
850
+ ]
851
+ }),
852
+ "warehouse-dusk": defineEnvironmentPreset({
853
+ preset: "warehouse-dusk",
854
+ scene: "warehouse",
855
+ timeOfDay: "dusk",
856
+ environmentMode: 13,
857
+ environmentIntensity: 0.7,
858
+ exposure: 1.16,
859
+ horizonColor: [0.7, 0.32, 0.24, 1],
860
+ zenithColor: [0.08, 0.1, 0.18, 1],
861
+ sunDirection: [-0.78, 0.18, 0.16],
862
+ sunColor: [2.4, 0.94, 0.48, 1],
863
+ ambientColor: [0.022, 0.024, 0.03, 1],
864
+ environmentLightSources: [
865
+ { id: "warehouse-dusk-door-glow", kind: "sodium-door", role: "key", direction: [-0.78, 0.18, 0.16], color: [1, 0.42, 0.2, 1], intensity: 2.4, angularRadiusRadians: 0.18 },
866
+ { id: "warehouse-dusk-fluorescent", kind: "fluorescent-strip", role: "fill", direction: [0, 0.95, -0.08], color: [0.72, 0.88, 1, 1], intensity: 1.35, angularRadiusRadians: 0.4 },
867
+ { id: "warehouse-dusk-emergency", kind: "emergency-beacon", role: "accent", direction: [0.2, 0.35, -0.8], color: [1, 0.08, 0.04, 1], intensity: 0.32 }
868
+ ]
869
+ }),
870
+ "warehouse-night": defineEnvironmentPreset({
871
+ preset: "warehouse-night",
872
+ scene: "warehouse",
873
+ timeOfDay: "night",
874
+ environmentMode: 14,
875
+ environmentIntensity: 0.58,
876
+ exposure: 1.28,
877
+ horizonColor: [0.06, 0.08, 0.12, 1],
878
+ zenithColor: [0.02, 0.03, 0.055, 1],
879
+ sunDirection: [0.1, 0.94, -0.12],
880
+ sunColor: [1.2, 1.65, 2.25, 1],
881
+ ambientColor: [0.014, 0.018, 0.024, 1],
882
+ environmentLightSources: [
883
+ { id: "warehouse-night-fluorescent", kind: "fluorescent-strip", role: "key", direction: [0.1, 0.94, -0.12], color: [0.68, 0.88, 1, 1], intensity: 2.25, angularRadiusRadians: 0.5 },
884
+ { id: "warehouse-night-emergency", kind: "emergency-beacon", role: "accent", direction: [-0.4, 0.3, 0.7], color: [1, 0.05, 0.025, 1], intensity: 0.4 },
885
+ { id: "warehouse-night-door-leak", kind: "window-portal", role: "rim", direction: [0.82, 0.08, -0.2], color: [0.12, 0.22, 0.42, 1], intensity: 0.34 }
886
+ ]
887
+ }),
888
+ "cavern-dawn": defineEnvironmentPreset({
889
+ preset: "cavern-dawn",
890
+ scene: "cavern",
891
+ timeOfDay: "dawn",
892
+ environmentMode: 15,
893
+ environmentIntensity: 0.62,
894
+ exposure: 1.24,
895
+ horizonColor: [0.5, 0.3, 0.2, 1],
896
+ zenithColor: [0.04, 0.07, 0.09, 1],
897
+ sunDirection: [0.72, 0.32, 0.26],
898
+ sunColor: [2.1, 1.22, 0.64, 1],
899
+ ambientColor: [0.018, 0.018, 0.016, 1],
900
+ environmentLightSources: [
901
+ { id: "cavern-dawn-mouth", kind: "cave-mouth", role: "key", direction: [0.72, 0.32, 0.26], color: [1, 0.58, 0.3, 1], intensity: 2.1, angularRadiusRadians: 0.24 },
902
+ { id: "cavern-dawn-torch", kind: "torch", role: "emissive", direction: [-0.35, 0.28, -0.6], color: [1, 0.42, 0.16, 1], intensity: 1.35, reach: 18 },
903
+ { id: "cavern-dawn-crystal", kind: "crystal", role: "accent", direction: [0.08, 0.22, 0.9], color: [0.22, 0.72, 1, 1], intensity: 0.28, reach: 10 }
904
+ ]
905
+ }),
906
+ "cavern-midday": defineEnvironmentPreset({
907
+ preset: "cavern-midday",
908
+ scene: "cavern",
909
+ timeOfDay: "midday",
910
+ environmentMode: 16,
911
+ environmentIntensity: 0.72,
912
+ exposure: 1.16,
913
+ horizonColor: [0.6, 0.56, 0.48, 1],
914
+ zenithColor: [0.08, 0.12, 0.14, 1],
915
+ sunDirection: [0.36, 0.82, 0.14],
916
+ sunColor: [3.4, 3.05, 2.2, 1],
917
+ ambientColor: [0.02, 0.022, 0.02, 1],
918
+ environmentLightSources: [
919
+ { id: "cavern-midday-mouth", kind: "cave-mouth", role: "key", direction: [0.36, 0.82, 0.14], color: [1, 0.9, 0.66, 1], intensity: 3.4, angularRadiusRadians: 0.18 },
920
+ { id: "cavern-midday-biolume", kind: "bioluminescence", role: "fill", direction: [-0.25, 0.25, 0.7], color: [0.1, 0.82, 0.64, 1], intensity: 0.46, reach: 14 },
921
+ { id: "cavern-midday-wet-rock", kind: "ground-bounce", role: "bounce", direction: [0.1, 0.2, -0.3], color: [0.18, 0.2, 0.18, 1], intensity: 0.22 }
922
+ ]
923
+ }),
924
+ "cavern-dusk": defineEnvironmentPreset({
925
+ preset: "cavern-dusk",
926
+ scene: "cavern",
927
+ timeOfDay: "dusk",
928
+ environmentMode: 17,
929
+ environmentIntensity: 0.56,
930
+ exposure: 1.32,
931
+ horizonColor: [0.46, 0.18, 0.14, 1],
932
+ zenithColor: [0.035, 0.045, 0.08, 1],
933
+ sunDirection: [-0.62, 0.22, 0.22],
934
+ sunColor: [1.55, 0.56, 0.28, 1],
935
+ ambientColor: [0.014, 0.014, 0.018, 1],
936
+ environmentLightSources: [
937
+ { id: "cavern-dusk-mouth", kind: "cave-mouth", role: "rim", direction: [-0.62, 0.22, 0.22], color: [1, 0.36, 0.18, 1], intensity: 1.55, angularRadiusRadians: 0.22 },
938
+ { id: "cavern-dusk-torch", kind: "torch", role: "key", direction: [0.32, 0.34, -0.54], color: [1, 0.38, 0.12, 1], intensity: 1.85, reach: 20 },
939
+ { id: "cavern-dusk-biolume", kind: "bioluminescence", role: "fill", direction: [-0.18, 0.18, 0.74], color: [0.08, 0.58, 0.72, 1], intensity: 0.34, reach: 12 }
940
+ ]
941
+ }),
942
+ "cavern-night": defineEnvironmentPreset({
943
+ preset: "cavern-night",
944
+ scene: "cavern",
945
+ timeOfDay: "night",
946
+ environmentMode: 18,
947
+ environmentIntensity: 0.5,
948
+ exposure: 1.45,
949
+ horizonColor: [0.025, 0.035, 0.06, 1],
950
+ zenithColor: [8e-3, 0.014, 0.03, 1],
951
+ sunDirection: [0.18, 0.28, -0.68],
952
+ sunColor: [1.9, 0.72, 0.24, 1],
953
+ ambientColor: [0.01, 0.012, 0.018, 1],
954
+ environmentLightSources: [
955
+ { id: "cavern-night-torch", kind: "torch", role: "key", direction: [0.18, 0.28, -0.68], color: [1, 0.36, 0.12, 1], intensity: 1.9, reach: 18 },
956
+ { id: "cavern-night-biolume", kind: "bioluminescence", role: "fill", direction: [-0.32, 0.16, 0.72], color: [0.06, 0.62, 0.76, 1], intensity: 0.52, reach: 16 },
957
+ { id: "cavern-night-lava", kind: "lava-fissure", role: "emissive", direction: [0.42, 0.12, 0.28], color: [1, 0.18, 0.04, 1], intensity: 0.8, reach: 12 }
958
+ ]
263
959
  })
264
960
  });
265
- function resolveEnvironmentPreset(name) {
961
+ var lightingEnvironmentPresetNames = Object.freeze(
962
+ Object.keys(environmentLightingPresets)
963
+ );
964
+ function resolveEnvironmentPreset(name, timeOfDay) {
266
965
  const presetName = typeof name === "string" && name.length > 0 ? name : "product-studio";
267
966
  const preset = environmentLightingPresets[presetName];
268
967
  if (!preset) {
968
+ if (lightingEnvironmentSceneNames.includes(presetName)) {
969
+ if (timeOfDay != null && !lightingEnvironmentTimeOfDayNames.includes(timeOfDay)) {
970
+ throw new Error(
971
+ `timeOfDay must be one of: ${lightingEnvironmentTimeOfDayNames.join(", ")}.`
972
+ );
973
+ }
974
+ const scenePresetName = `${presetName}-${timeOfDay ?? "midday"}`;
975
+ const scenePreset = environmentLightingPresets[scenePresetName];
976
+ if (scenePreset) {
977
+ return scenePreset;
978
+ }
979
+ }
269
980
  throw new Error(
270
981
  `Unknown lighting environment preset "${presetName}". Expected one of: ${lightingEnvironmentPresetNames.join(", ")}.`
271
982
  );
@@ -277,21 +988,36 @@ function estimateEnvironmentColor(config) {
277
988
  const zenithWeight = 1 - horizonWeight;
278
989
  const glowWeight = 0.055;
279
990
  const intensity = Math.max(config.environmentIntensity, 1e-4);
280
- return freezeVec4([
991
+ return ensureNonNullColor([
281
992
  (config.horizonColor[0] * horizonWeight + config.zenithColor[0] * zenithWeight + config.sunColor[0] * glowWeight) * intensity,
282
993
  (config.horizonColor[1] * horizonWeight + config.zenithColor[1] * zenithWeight + config.sunColor[1] * glowWeight) * intensity,
283
994
  (config.horizonColor[2] * horizonWeight + config.zenithColor[2] * zenithWeight + config.sunColor[2] * glowWeight) * intensity,
284
995
  1
285
- ]);
996
+ ], config.dominantLightSource?.radiance ?? config.sunColor);
286
997
  }
287
998
  function createEnvironmentLightingConfig(options = {}) {
288
- const preset = resolveEnvironmentPreset(options.preset ?? options.name);
999
+ const preset = resolveEnvironmentPreset(
1000
+ options.preset ?? options.name ?? options.scene,
1001
+ options.timeOfDay
1002
+ );
1003
+ const environmentPortals = normalizeEnvironmentPortals(
1004
+ options.environmentPortals ?? options.portals
1005
+ );
1006
+ const environmentMap = normalizeEnvironmentMap(
1007
+ options.environmentMap ?? options.hdri ?? preset.environmentMap
1008
+ );
1009
+ const environmentPortalMode = normalizeEnvironmentPortalMode(
1010
+ options.environmentPortalMode ?? options.portalMode,
1011
+ environmentPortals.length > 0
1012
+ );
289
1013
  const environmentIntensity = Math.max(
290
1014
  readFinite(options.environmentIntensity ?? options.intensity, preset.environmentIntensity),
291
1015
  1e-4
292
1016
  );
293
- const config = {
1017
+ const baseConfig = {
294
1018
  preset: preset.preset,
1019
+ scene: preset.scene,
1020
+ timeOfDay: preset.timeOfDay,
295
1021
  profile: typeof options.profile === "string" ? options.profile : defaultLightingProfile,
296
1022
  environmentMode: Math.max(0, Math.trunc(readFinite(options.environmentMode, preset.environmentMode))),
297
1023
  environmentIntensity,
@@ -302,15 +1028,49 @@ function createEnvironmentLightingConfig(options = {}) {
302
1028
  normalizeVector3(options.sunDirection, preset.sunDirection)
303
1029
  ),
304
1030
  sunColor: readColor(options.sunColor, preset.sunColor),
305
- ambientColor: readColor(options.ambientColor, preset.ambientColor)
1031
+ ambientColor: readColor(options.ambientColor, preset.ambientColor),
1032
+ sunlitBaseline: Math.max(
1033
+ 0,
1034
+ readFinite(options.sunlitBaseline ?? options.daylightBaseline, preset.sunlitBaseline)
1035
+ ),
1036
+ environmentPortalMode,
1037
+ environmentPortals,
1038
+ environmentMap
1039
+ };
1040
+ const environmentLightSources = normalizeEnvironmentLightSources(
1041
+ options.environmentLightSources ?? options.lightSources,
1042
+ preset,
1043
+ baseConfig
1044
+ );
1045
+ const dominantLightSource = findDominantEnvironmentLightSource(
1046
+ environmentLightSources
1047
+ );
1048
+ const config = {
1049
+ ...baseConfig,
1050
+ environmentLightSources,
1051
+ lightSources: environmentLightSources,
1052
+ dominantLightSource
306
1053
  };
307
1054
  const environmentColor = estimateEnvironmentColor(config);
1055
+ const environmentMissLighting = createEnvironmentMissLighting(
1056
+ dominantLightSource,
1057
+ environmentColor
1058
+ );
308
1059
  return Object.freeze({
309
1060
  ...config,
310
1061
  environmentColor,
1062
+ environmentMissLighting,
311
1063
  wavefront: Object.freeze({
312
1064
  environmentColor,
313
1065
  ambientColor: config.ambientColor,
1066
+ sunlitBaseline: config.sunlitBaseline,
1067
+ environmentPortalMode: config.environmentPortalMode,
1068
+ environmentPortals: config.environmentPortals,
1069
+ environmentMap: config.environmentMap,
1070
+ environmentLightSources: config.environmentLightSources,
1071
+ lightSources: config.environmentLightSources,
1072
+ dominantLightSource,
1073
+ environmentMissLighting,
314
1074
  environmentLighting: Object.freeze({
315
1075
  horizonColor: config.horizonColor,
316
1076
  zenithColor: config.zenithColor,
@@ -318,7 +1078,15 @@ function createEnvironmentLightingConfig(options = {}) {
318
1078
  sunColor: config.sunColor,
319
1079
  intensity: config.environmentIntensity,
320
1080
  mode: config.environmentMode,
321
- exposure: config.exposure
1081
+ exposure: config.exposure,
1082
+ sunlitBaseline: config.sunlitBaseline,
1083
+ environmentPortalMode: config.environmentPortalMode,
1084
+ environmentPortalCount: config.environmentPortals.length,
1085
+ environmentMap: config.environmentMap,
1086
+ environmentLightSources: config.environmentLightSources,
1087
+ environmentLightSourceCount: config.environmentLightSources.length,
1088
+ dominantLightSource,
1089
+ environmentMissLighting
322
1090
  })
323
1091
  })
324
1092
  });
@@ -328,6 +1096,14 @@ function createWavefrontEnvironmentLightingOptions(options = {}) {
328
1096
  return Object.freeze({
329
1097
  environmentColor: config.wavefront.environmentColor,
330
1098
  ambientColor: config.wavefront.ambientColor,
1099
+ sunlitBaseline: config.wavefront.sunlitBaseline,
1100
+ environmentPortalMode: config.wavefront.environmentPortalMode,
1101
+ environmentPortals: config.wavefront.environmentPortals,
1102
+ environmentMap: config.wavefront.environmentMap,
1103
+ environmentLightSources: config.wavefront.environmentLightSources,
1104
+ lightSources: config.wavefront.environmentLightSources,
1105
+ dominantLightSource: config.wavefront.dominantLightSource,
1106
+ environmentMissLighting: config.wavefront.environmentMissLighting,
331
1107
  environmentLighting: config.wavefront.environmentLighting,
332
1108
  lightingEnvironment: config
333
1109
  });
@@ -1462,7 +2238,12 @@ async function loadLightingProfileWorkerPlan(profileName = defaultLightingProfil
1462
2238
  getLightingTechniqueWorkerManifest,
1463
2239
  lightingDebugOwner,
1464
2240
  lightingDistanceBands,
2241
+ lightingEnvironmentLightSourceKinds,
2242
+ lightingEnvironmentPortalModes,
2243
+ lightingEnvironmentPortalShapes,
1465
2244
  lightingEnvironmentPresetNames,
2245
+ lightingEnvironmentSceneNames,
2246
+ lightingEnvironmentTimeOfDayNames,
1466
2247
  lightingJobLabels,
1467
2248
  lightingJobs,
1468
2249
  lightingPreludeWgslUrl,