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