@plasius/gpu-lighting 0.2.0 → 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/CHANGELOG.md CHANGED
@@ -20,6 +20,27 @@ The format is based on **[Keep a Changelog](https://keepachangelog.com/en/1.1.0/
20
20
  - **Security**
21
21
  - (placeholder)
22
22
 
23
+ ## [0.2.2] - 2026-06-11
24
+
25
+ - **Added**
26
+ - Added `environmentMap`/`hdri` passthrough in wavefront lighting options so
27
+ renderers can use HDRI/equirectangular radiance textures as environment
28
+ light sources instead of relying primarily on static ambient colours.
29
+ - Added `sunlitBaseline` to environment lighting presets and wavefront
30
+ lighting options so renderers can apply a time-of-day daylight floor at
31
+ terminal path collisions without raising ambient residual colour.
32
+ - (placeholder)
33
+
34
+ - **Changed**
35
+ - Reduced ambient residual strength for the grass-field, forest, warehouse,
36
+ and cavern environment preset families to avoid low-sample whitewash.
37
+
38
+ - **Fixed**
39
+ - (placeholder)
40
+
41
+ - **Security**
42
+ - (placeholder)
43
+
23
44
  ## [0.2.0] - 2026-06-06
24
45
 
25
46
  - **Added**
@@ -354,5 +375,6 @@ The format is based on **[Keep a Changelog](https://keepachangelog.com/en/1.1.0/
354
375
  [0.1.16]: https://github.com/Plasius-LTD/gpu-lighting/releases/tag/v0.1.16
355
376
  [0.1.17]: https://github.com/Plasius-LTD/gpu-lighting/releases/tag/v0.1.17
356
377
  [0.1.19]: https://github.com/Plasius-LTD/gpu-lighting/releases/tag/v0.1.19
357
- [Unreleased]: https://github.com/Plasius-LTD/gpu-lighting/compare/v0.2.0...HEAD
378
+ [Unreleased]: https://github.com/Plasius-LTD/gpu-lighting/compare/v0.2.2...HEAD
358
379
  [0.2.0]: https://github.com/Plasius-LTD/gpu-lighting/releases/tag/v0.2.0
380
+ [0.2.2]: https://github.com/Plasius-LTD/gpu-lighting/releases/tag/v0.2.2
package/README.md CHANGED
@@ -141,7 +141,12 @@ console.log(wavefrontLighting.environmentMissLighting.startingPoint);
141
141
  `createEnvironmentLightingConfig(...)` owns the reusable sky/environment
142
142
  semantics: horizon and zenith colours, key-light direction, key-light colour,
143
143
  environment intensity, exposure, ambient residual colour, and optional
144
- environment-light portals.
144
+ environment-light portals. The grass-field, forest, warehouse, and cavern
145
+ families use restrained ambient residual scaling so low-sample renderers keep
146
+ some final-bounce colour without washing dark materials toward white. They also
147
+ publish `sunlitBaseline`, a scene-scaled time-of-day daylight floor that
148
+ renderers can use at terminal path collisions without raising the global
149
+ ambient colour.
145
150
 
146
151
  Preset families now cover:
147
152
 
@@ -154,14 +159,18 @@ Callers can pass the combined `preset` name directly or pass `scene` plus
154
159
  `timeOfDay`; scene-only aliases default to `midday`.
155
160
 
156
161
  Each preset publishes `scene`, `timeOfDay`, normalized
157
- `environmentLightSources`, a `dominantLightSource`, and
162
+ `sunlitBaseline`, `environmentLightSources`, a `dominantLightSource`, and
158
163
  `environmentMissLighting`. Source metadata includes source kind, role, direction,
159
164
  position, colour, intensity, radiance, luminance, reach, and angular radius.
160
165
  Renderers can use `environmentMissLighting` when a path ray misses scene
161
166
  geometry: the miss has an inferred source colour/brightness and a stable
162
167
  `startingPoint` of `environment-miss` instead of an unbounded null/negative sky
163
168
  sample. Emissive material hits remain explicit light-source hits and should not
164
- be double-counted by environment inference.
169
+ be double-counted by environment inference. Callers can also pass an
170
+ `environmentMap`/`hdri` descriptor; the lighting config preserves it in
171
+ `createWavefrontEnvironmentLightingOptions(...)` so the wavefront renderer can
172
+ sample an equirectangular radiance map for environment misses and ambient
173
+ residuals instead of relying primarily on static ambient values.
165
174
 
166
175
  Portals describe physical openings such as windows where outside radiance can
167
176
  enter an interior. They are normalized as rectangle apertures with position,
package/dist/index.cjs CHANGED
@@ -235,9 +235,37 @@ var lightingDistanceBands = Object.freeze([
235
235
  ]);
236
236
  var lightingWorkerQueueClass = "lighting";
237
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
+ });
238
258
  function freezeVec4(value) {
239
259
  return Object.freeze([value[0], value[1], value[2], value[3] ?? 1]);
240
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
+ }
241
269
  function normalizeVector3(value, fallback) {
242
270
  if (!Array.isArray(value) || value.length < 3) {
243
271
  return [...fallback];
@@ -402,6 +430,22 @@ function normalizeEnvironmentPortals(value) {
402
430
  }
403
431
  return Object.freeze(value.map(normalizeEnvironmentPortal));
404
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
+ }
405
449
  function freezeLightSourceSpec(source) {
406
450
  return Object.freeze({
407
451
  ...source,
@@ -411,15 +455,27 @@ function freezeLightSourceSpec(source) {
411
455
  });
412
456
  }
413
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
+ );
414
469
  return Object.freeze({
415
470
  ...spec,
416
- scene: spec.scene ?? "studio",
417
- timeOfDay: spec.timeOfDay ?? "midday",
471
+ scene,
472
+ timeOfDay,
418
473
  horizonColor: freezeVec4(spec.horizonColor),
419
474
  zenithColor: freezeVec4(spec.zenithColor),
420
475
  sunDirection: Object.freeze(normalizeVector3(spec.sunDirection, [0, 1, 0])),
421
476
  sunColor: freezeVec4(spec.sunColor),
422
- ambientColor: freezeVec4(spec.ambientColor),
477
+ ambientColor: freezeVec4(scaleVec4(spec.ambientColor, ambientScale)),
478
+ sunlitBaseline,
423
479
  environmentLightSources: Object.freeze(
424
480
  (spec.environmentLightSources ?? []).map(freezeLightSourceSpec)
425
481
  )
@@ -947,6 +1003,9 @@ function createEnvironmentLightingConfig(options = {}) {
947
1003
  const environmentPortals = normalizeEnvironmentPortals(
948
1004
  options.environmentPortals ?? options.portals
949
1005
  );
1006
+ const environmentMap = normalizeEnvironmentMap(
1007
+ options.environmentMap ?? options.hdri ?? preset.environmentMap
1008
+ );
950
1009
  const environmentPortalMode = normalizeEnvironmentPortalMode(
951
1010
  options.environmentPortalMode ?? options.portalMode,
952
1011
  environmentPortals.length > 0
@@ -970,8 +1029,13 @@ function createEnvironmentLightingConfig(options = {}) {
970
1029
  ),
971
1030
  sunColor: readColor(options.sunColor, preset.sunColor),
972
1031
  ambientColor: readColor(options.ambientColor, preset.ambientColor),
1032
+ sunlitBaseline: Math.max(
1033
+ 0,
1034
+ readFinite(options.sunlitBaseline ?? options.daylightBaseline, preset.sunlitBaseline)
1035
+ ),
973
1036
  environmentPortalMode,
974
- environmentPortals
1037
+ environmentPortals,
1038
+ environmentMap
975
1039
  };
976
1040
  const environmentLightSources = normalizeEnvironmentLightSources(
977
1041
  options.environmentLightSources ?? options.lightSources,
@@ -999,8 +1063,10 @@ function createEnvironmentLightingConfig(options = {}) {
999
1063
  wavefront: Object.freeze({
1000
1064
  environmentColor,
1001
1065
  ambientColor: config.ambientColor,
1066
+ sunlitBaseline: config.sunlitBaseline,
1002
1067
  environmentPortalMode: config.environmentPortalMode,
1003
1068
  environmentPortals: config.environmentPortals,
1069
+ environmentMap: config.environmentMap,
1004
1070
  environmentLightSources: config.environmentLightSources,
1005
1071
  lightSources: config.environmentLightSources,
1006
1072
  dominantLightSource,
@@ -1013,8 +1079,10 @@ function createEnvironmentLightingConfig(options = {}) {
1013
1079
  intensity: config.environmentIntensity,
1014
1080
  mode: config.environmentMode,
1015
1081
  exposure: config.exposure,
1082
+ sunlitBaseline: config.sunlitBaseline,
1016
1083
  environmentPortalMode: config.environmentPortalMode,
1017
1084
  environmentPortalCount: config.environmentPortals.length,
1085
+ environmentMap: config.environmentMap,
1018
1086
  environmentLightSources: config.environmentLightSources,
1019
1087
  environmentLightSourceCount: config.environmentLightSources.length,
1020
1088
  dominantLightSource,
@@ -1028,8 +1096,10 @@ function createWavefrontEnvironmentLightingOptions(options = {}) {
1028
1096
  return Object.freeze({
1029
1097
  environmentColor: config.wavefront.environmentColor,
1030
1098
  ambientColor: config.wavefront.ambientColor,
1099
+ sunlitBaseline: config.wavefront.sunlitBaseline,
1031
1100
  environmentPortalMode: config.wavefront.environmentPortalMode,
1032
1101
  environmentPortals: config.wavefront.environmentPortals,
1102
+ environmentMap: config.wavefront.environmentMap,
1033
1103
  environmentLightSources: config.wavefront.environmentLightSources,
1034
1104
  lightSources: config.wavefront.environmentLightSources,
1035
1105
  dominantLightSource: config.wavefront.dominantLightSource,