rayzee 9.0.0 → 9.1.0

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.
Files changed (94) hide show
  1. package/README.md +139 -8
  2. package/dist/{NeuralRetouch-CYOJ21Wn.js → NeuralRetouch-BRquqfmZ.js} +1 -1
  3. package/dist/{NeuralSuperRes-CQLCLpcC.js → NeuralSuperRes-CbNvQjCw.js} +3 -2
  4. package/dist/{ToneMapGPU-BVE852iN.js → ToneMapGPU-DpUZDMbQ.js} +2 -1
  5. package/dist/rayzee.es.js +10344 -5334
  6. package/dist/rayzee.umd.js +265 -265
  7. package/package.json +1 -1
  8. package/src/AssetConfig.js +4 -0
  9. package/src/EngineDefaults.js +38 -56
  10. package/src/EngineEvents.js +3 -0
  11. package/src/EngineIssues.js +6 -0
  12. package/src/Headless.js +3 -1
  13. package/src/Passes/AIUpscaler.js +2 -1
  14. package/src/Passes/OIDNDenoiser.js +3 -6
  15. package/src/PathTracerApp.js +290 -19
  16. package/src/Processor/ArchiveCache.js +120 -0
  17. package/src/Processor/ArchiveReader.js +179 -32
  18. package/src/Processor/AssetLoader.js +514 -76
  19. package/src/Processor/AtmosphereModel.js +465 -0
  20. package/src/Processor/BVHBuilder.js +4 -1
  21. package/src/Processor/BVHLeafFold.js +100 -0
  22. package/src/Processor/BVHRefitter.js +98 -214
  23. package/src/Processor/ChunkedRecords.js +189 -4
  24. package/src/Processor/EmissiveTriangleBuilder.js +8 -0
  25. package/src/Processor/GeometryExtractor.js +238 -40
  26. package/src/Processor/InstanceTable.js +55 -37
  27. package/src/Processor/PBRT/PBRTCurves.js +104 -27
  28. package/src/Processor/PBRT/PBRTParser.js +132 -22
  29. package/src/Processor/PBRT/PBRTSceneBuilder.js +192 -49
  30. package/src/Processor/PBRT/buffers.js +27 -0
  31. package/src/Processor/PBRT/index.js +55 -15
  32. package/src/Processor/PackedRayBuffer.js +10 -13
  33. package/src/Processor/ParallelBVHBuilder.js +36 -15
  34. package/src/Processor/PhysicalSky.js +308 -0
  35. package/src/Processor/QueueManager.js +1 -0
  36. package/src/Processor/SceneProcessor.js +1132 -181
  37. package/src/Processor/SplitBLAS.js +249 -0
  38. package/src/Processor/SunPosition.js +41 -0
  39. package/src/Processor/TextureCreator.js +21 -0
  40. package/src/Processor/Workers/AIUpscalerWorker.js +79 -52
  41. package/src/Processor/Workers/BVHWorker.js +17 -13
  42. package/src/Processor/ZipReader.js +207 -0
  43. package/src/RenderSettings.js +38 -0
  44. package/src/SceneState/SceneState.js +367 -0
  45. package/src/SceneState/portable.js +52 -0
  46. package/src/Stages/NormalDepth.js +7 -6
  47. package/src/Stages/PathTracer.js +108 -4
  48. package/src/Stages/PathTracerStage.js +251 -104
  49. package/src/Storage/BLASCache.js +190 -0
  50. package/src/Storage/CDFCache.js +77 -0
  51. package/src/Storage/DownloadCache.js +266 -0
  52. package/src/Storage/GeometrySpill.js +217 -0
  53. package/src/Storage/SceneGraphCodec.js +503 -0
  54. package/src/Storage/SpillStore.js +112 -0
  55. package/src/Storage/StorageManager.js +934 -0
  56. package/src/Storage/StorageOps.js +137 -0
  57. package/src/Storage/StorageWorker.js +37 -0
  58. package/src/Storage/events.js +29 -0
  59. package/src/Storage/identity.js +77 -0
  60. package/src/Storage/index.js +9 -0
  61. package/src/Storage/inlineTransport.js +24 -0
  62. package/src/Storage/locks.js +99 -0
  63. package/src/Storage/openStorage.js +87 -0
  64. package/src/Storage/sceneCachePolicy.js +12 -0
  65. package/src/Storage/shared.js +9 -0
  66. package/src/Storage/transport.js +62 -0
  67. package/src/TSL/Atmosphere.js +684 -0
  68. package/src/TSL/BVHTraversal.js +288 -239
  69. package/src/TSL/Common.js +11 -2
  70. package/src/TSL/Displacement.js +6 -6
  71. package/src/TSL/EmissiveSampling.js +5 -5
  72. package/src/TSL/EnvironmentCDF.js +176 -0
  73. package/src/TSL/GenerateKernel.js +3 -3
  74. package/src/TSL/HitFacet.js +4 -4
  75. package/src/TSL/LightsDirect.js +8 -8
  76. package/src/TSL/LightsSampling.js +55 -37
  77. package/src/TSL/Random.js +1 -0
  78. package/src/TSL/ShadeKernel.js +75 -19
  79. package/src/TSL/Sun.js +40 -0
  80. package/src/TSL/TextureSampling.js +6 -7
  81. package/src/index.js +18 -0
  82. package/src/managers/CameraManager.js +169 -1
  83. package/src/managers/EnvironmentManager.js +263 -33
  84. package/src/managers/GoboManager.js +19 -8
  85. package/src/managers/IESManager.js +3 -3
  86. package/src/managers/LightManager.js +98 -5
  87. package/src/managers/MaterialDataManager.js +22 -2
  88. package/src/managers/TransformManager.js +26 -0
  89. package/src/managers/UniformManager.js +5 -3
  90. package/src/managers/VideoRenderManager.js +3 -1
  91. package/src/managers/timeline/CameraTrack.js +22 -0
  92. package/src/managers/timeline/TimelineManager.js +14 -0
  93. package/src/version.js +3 -0
  94. package/src/Processor/ProceduralSky.js +0 -291
package/README.md CHANGED
@@ -294,9 +294,12 @@ configureAssets({
294
294
  ocioRuntimeFactory: () => import('@bb-studio/ocio'), // or: ocioRuntimeUrl: '/vendor/ocio/index.js'
295
295
  ocioWasmUrl: '/vendor/ocio/ocio-wasm.wasm', // optional override for the .wasm
296
296
 
297
- // Prefix for engine-managed IndexedDB stores. Set to a unique value if multiple
298
- // apps embed the engine on the same origin to avoid cache collisions.
297
+ // Names the engine's on-disk storage (an OPFS directory). Set a unique value if several
298
+ // apps embed the engine on the same origin, so their caches stay apart.
299
299
  cacheNamespace: 'my-app',
300
+
301
+ // On-disk storage: 'auto' (default) where the browser has it, false for none.
302
+ storage: 'auto',
300
303
  });
301
304
 
302
305
  const engine = new PathTracerApp(canvas);
@@ -321,6 +324,8 @@ const engine = new PathTracerApp(canvas, options?)
321
324
  | `options.strict` | `boolean` | Throw an `EngineIssueError` where the engine would otherwise degrade and carry on (default: `false`). See [Degradation contract](#degradation-contract). |
322
325
  | `options.profile` | `string` | `'viewer'` (default) or `'physical'` — product tuning that is not a physical constant: area-light scale, environment rotation, tone mapping, saturation. An unknown name throws. |
323
326
  | `options.maxSceneBytes` | `number` | Raise or lower the CPU memory ceiling a scene may need before the engine refuses it (default 9,216 MB). See [Memory monitoring](#memory-monitoring). |
327
+ | `options.storage` | `false \| 'auto' \| StorageManager` | On-disk storage (default: `configureAssets( { storage } )`). A manager you pass stays yours to dispose. See [On-disk storage](#on-disk-storage-opfs). |
328
+ | `options.memorySpill` | `boolean` | Experimental, default `false`: build a large static scene through disk — triangle records, BLAS nodes and the three.js geometry are written out as the build finishes with them — and raise the pbrt triangle and placement caps to 60M / 8M. See [On-disk storage](#on-disk-storage-opfs). |
324
329
 
325
330
  The engine creates and mounts everything it needs (denoiser canvas, tile/HUD overlay) into a single parent on `init()`. Performance HUDs (e.g. `stats-gl`) are not bundled — listen to `EngineEvents.FRAME` and tick your own panel.
326
331
 
@@ -392,10 +397,20 @@ try {
392
397
  }
393
398
  ```
394
399
 
395
- Per-load options for pbrt archives: `promptBytes` moves that 4 GB line, `maxTriangles` (default
396
- 45M) and `maxPlacements` (default 6M) cap the build — past either, placements are skipped and the
397
- build reports itself truncated. 45M is the highest rung measured to survive; raising it is a
398
- deliberate act on a fresh browser tab.
400
+ Per-load options for pbrt archives:
401
+
402
+ | Option | Default | Effect |
403
+ |---|---|---|
404
+ | `promptBytes` | 4 GB | moves the line past which a multi-element archive asks for elements |
405
+ | `maxTriangles` | 45M (60M with `memorySpill`) | past it, placements are skipped and the build reports itself truncated |
406
+ | `maxPlacements` | 6M (8M with `memorySpill`) | the same, for placements |
407
+ | `curveTolerance` | 0.05 | how far a curve segment may stray, × the curve's half-width; curves become strips with adaptive segments. `0` gives the old uniform strips bit for bit |
408
+ | `instanceIncludes` | `true` | a file included again under the same material, with no side effects, is placed as an instance of its first reading instead of being read and stored again |
409
+
410
+ 45M is the highest rung measured to survive without the spill; raising either cap is a deliberate
411
+ act on a fresh browser tab. With `memorySpill`, 80M stored triangles (4.35M placements) have loaded
412
+ and rendered; an 89M load ran out of memory while parsing, and WebGPU's 4 GB buffer limit stops the
413
+ triangle data at 89.5M in any case.
399
414
 
400
415
  #### Settings
401
416
 
@@ -659,12 +674,29 @@ engine.environmentManager.texture // The loaded environment texture
659
674
  await engine.loadEnvironment(url) // Load HDR/EXR environment map (method on engine)
660
675
  await engine.environmentManager.setEnvironmentMap(tex) // Set a custom environment texture
661
676
  await engine.environmentManager.setMode(mode) // 'hdri' | 'procedural' | 'gradient' | 'color'
662
- await engine.environmentManager.generateProcedural() // Preetham-model sky
677
+ await engine.environmentManager.generateProcedural() // Physical sky: spectral, multiple scattering, analytic sun
663
678
  await engine.environmentManager.generateGradient() // Gradient sky
664
679
  await engine.environmentManager.generateSolid() // Solid color sky
665
680
  engine.environmentManager.markDirty() // Flag environment for GPU re-upload
666
681
  ```
667
682
 
683
+ The physical sky (mode `'procedural'`) is set through `params`, then baked. It is baked and
684
+ importance-sampled entirely on the GPU (~1.6 ms per sun move), so bake on every slider event rather
685
+ than debouncing: requests made in one task become one bake, and the promise resolves once the
686
+ environment has caught up. The sun is drawn and sampled as a light of its own, not from the texture.
687
+
688
+ ```js
689
+ import { sunPosition, dayOfYearForMonth } from 'rayzee';
690
+
691
+ const p = engine.environmentManager.params;
692
+ const { azimuth, elevation } = sunPosition( { hours: 17.5, dayOfYear: dayOfYearForMonth( 6 ), latitude: 40 } );
693
+ const az = ( 180 - azimuth ) * Math.PI / 180, el = elevation * Math.PI / 180; // north along −Z, east along +X
694
+ p.skySunDirection.set( Math.cos( el ) * Math.sin( az ), Math.sin( el ), Math.cos( el ) * Math.cos( az ) );
695
+ p.skyTurbidity = 3; // haze, 1–10; also skyOzone (Dobson units), skyAirDensity (× Earth's),
696
+ // skyGroundAlbedo (Color), skyAltitude (m), skySunSize (°), skySunStrength
697
+ await engine.environmentManager.generateProcedural();
698
+ ```
699
+
668
700
  ### engine.denoisingManager
669
701
 
670
702
  Denoiser strategy, ASVGF, OIDN, upscaler, and auto-exposure.
@@ -897,7 +929,8 @@ Before extraction the engine prices the scene and applies two lines, both record
897
929
 
898
930
  Raise or lower the hard line with `new PathTracerApp(canvas, { maxSceneBytes })`. The estimate runs
899
931
  low at the very top of its range, so the per-load `maxTriangles` cap (45M) is the more reliable
900
- guard on a scene of that size.
932
+ guard on a scene of that size. With `memorySpill` the estimate leaves out what the build keeps on
933
+ disk (the BVH, and triangle records past what a streamed build holds at once).
901
934
 
902
935
  ---
903
936
 
@@ -968,6 +1001,87 @@ precision, the model, kernel capabilities, tile state and resource counts — wh
968
1001
  confirm FP16 actually engaged on a given GPU rather than inferring it from the device's feature
969
1002
  list. Both need `timestamp-query`, and `getDenoiseProfile()` returns `null` when OIDN is not set up.
970
1003
 
1004
+ ### On-disk Storage (OPFS)
1005
+
1006
+ `engine.storage` is a `StorageManager` over the browser's origin private file system, or `null` where
1007
+ there is none (a private window, Node) — everything works without it, only slower. The engine keeps
1008
+ its caches there: downloads (models, skies, OIDN weights, STBN atlases — revalidated with `HEAD`),
1009
+ unpacked `.tar.gz` archives and archive indexes, built scenes (reopened without rebuilding BVHs when
1010
+ the first build took ≥ 10 s), and environment sampling tables. Caches share a budget of 30 % of the
1011
+ quota and are evicted least-recently-used; `engine.storage.usage()` reports each area.
1012
+
1013
+ A host keeps its own data beside them:
1014
+
1015
+ ```js
1016
+ import { STORAGE_KIND } from 'rayzee';
1017
+
1018
+ engine.storage.defineArea( 'renders', { kind: STORAGE_KIND.USER } ); // never evicted
1019
+ const writer = await engine.storage.area( 'renders' ).create( 'render:42', { label: 'Render 42' } );
1020
+ await writer.writeFile( 'image.png', blob );
1021
+ await writer.commit(); // meta.json last: all or nothing
1022
+
1023
+ const entry = await engine.storage.area( 'renders' ).open( 'render:42' );
1024
+ const file = await entry.file( 'image.png' );
1025
+ entry.release();
1026
+ ```
1027
+
1028
+ `loadFile( url )` and `loadModel( url, { cacheKey } )` download through the cache — pass `cacheKey` for
1029
+ a link that expires (a signed URL). `fetchFile( url, storage )` / `cachedObjectURL( url )` do the same
1030
+ for a host's own assets. Failures record `storage.*` issues and fall back to memory; storage never
1031
+ throws for being absent or full.
1032
+
1033
+ **Memory spill (experimental).** With `memorySpill: true`, a static scene of more than one 64 MB chunk
1034
+ is built through disk, so its large arrays are never all in memory at once:
1035
+
1036
+ - Extraction and BVH building run together. Each stored range of triangles goes to a BLAS worker as
1037
+ soon as it is written, and extraction waits while more than 1.5 GB of triangle records are held.
1038
+ On the 55.7M-triangle Moana subset the build peak fell from 6.6 to 4.1 GB.
1039
+ - The three.js geometry goes to disk after the build last reads it, and comes back when the build
1040
+ ends. On a 70M-triangle scene the page held 0.84 GB after extraction instead of 4.07 GB.
1041
+ - Each triangle chunk and BLAS goes to the GPU, then to disk. At 50M triangles the page settles at
1042
+ 7.2 GB instead of 9.1 GB.
1043
+
1044
+ With or without the spill, a mesh past 2M triangles is built as spatial pieces of ≤ 512k triangles
1045
+ on a worker pool and joined under the tree that split them, so no build holds a second copy of it.
1046
+
1047
+ The render is unchanged. Visibility and rigid moves need nothing read back. Material edits that
1048
+ rewrite triangles (side, transparency, emission), and refits, read it back first. `refitBLASes`
1049
+ throws on a spilled scene until `await engine.ensureSceneResident()`.
1050
+
1051
+ ### Saving Scene State
1052
+
1053
+ ```js
1054
+ const state = engine.exportSceneState(); // JSON-safe: settings, sky, colour, lights, cameras,
1055
+ // timeline keys, material edits, hidden and moved objects
1056
+ const source = engine.sceneSource; // { kind: 'url', url, cacheKey } | { kind: 'local-file', file } | ...
1057
+
1058
+ // later, after loading the same model again:
1059
+ const { skipped } = await engine.importSceneState( state, {
1060
+ resolve: async ( request ) => {
1061
+ // { kind: 'environment', source } → a File, a URL or null (the engine loads URL skies itself)
1062
+ // { kind: 'colorConfig', config } → true once you have loaded it (built-in configs load themselves)
1063
+ return null;
1064
+ },
1065
+ } );
1066
+ ```
1067
+
1068
+ Objects, materials and cameras are matched by position in the scene plus a name check — UUIDs
1069
+ change on every load — so a different model keeps its own objects and materials and the rest still
1070
+ applies; `skipped` lists what could not be put back. Texture swaps on materials are not included yet.
1071
+
1072
+ ### Render Checkpoints
1073
+
1074
+ ```js
1075
+ const checkpoint = await engine.captureRenderCheckpoint(); // accumulation + the counters that pick the next sample
1076
+ // ...a reload later, the same scene state restored and one frame rendered at the same size:
1077
+ engine.restoreRenderCheckpoint( checkpoint );
1078
+ engine.wake(); // or await engine.renderFrames( n, { reset: false } )
1079
+ ```
1080
+
1081
+ In deterministic mode the continued render is bit-identical to one that never stopped. A checkpoint
1082
+ is ~60 bytes a pixel (252 MB at 2048²): the accumulated colour and aux buffers as RGBA32F plus three
1083
+ per-pixel convergence buffers.
1084
+
971
1085
  ---
972
1086
 
973
1087
  ### Events
@@ -1039,6 +1153,7 @@ import {
1039
1153
  CAMERA_PRESETS,
1040
1154
  CAMERA_RANGES,
1041
1155
  SKY_PRESETS,
1156
+ DEFAULT_SUN_PATH,
1042
1157
  AUTO_FOCUS_MODES,
1043
1158
  AF_DEFAULTS,
1044
1159
  TRIANGLE_DATA_LAYOUT,
@@ -1063,12 +1178,28 @@ import {
1063
1178
  displayCanvasFit,
1064
1179
  } from 'rayzee';
1065
1180
 
1181
+ // Where the sun stands for a solar time, date and latitude (degrees; azimuth clockwise from north)
1182
+ import { sunPosition, timeForSunElevation, dayOfYearForMonth } from 'rayzee';
1183
+
1066
1184
  // Leveled/namespaced logging, shared with the workers
1067
1185
  import { Logger, createLogger, fmt, LOG_LEVELS } from 'rayzee';
1068
1186
 
1069
1187
  // Asset URL / cache namespace overrides
1070
1188
  import { configureAssets, getAssetConfig } from 'rayzee';
1071
1189
 
1190
+ // On-disk storage (OPFS): caches, host areas, downloads, file identity
1191
+ import {
1192
+ openStorage, StorageManager, STORAGE_KIND, ENGINE_AREAS, acquireLock, heldLockNames,
1193
+ fileIdentity, identityKey, sameIdentity,
1194
+ DownloadCache, DOWNLOAD_POLICY, fetchFile, nameFromUrl, cachedObjectURL,
1195
+ } from 'rayzee';
1196
+
1197
+ // Archives read in place, one entry at a time
1198
+ import { openZip, readZipDirectory } from 'rayzee';
1199
+
1200
+ // Scene state as plain data (engine.exportSceneState), and the engine version as built
1201
+ import { SCENE_STATE_VERSION, toPortable, fromPortable, VERSION } from 'rayzee';
1202
+
1072
1203
  // Advanced: managers & pipeline
1073
1204
  import {
1074
1205
  RenderSettings,
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./rolldown-runtime-CAFD8bLK.js";
2
- import { S as t, t as n, y as r } from "./ToneMapGPU-BVE852iN.js";
2
+ import { S as t, t as n, y as r } from "./ToneMapGPU-DpUZDMbQ.js";
3
3
  //#region src/neural/NeuralRetouch.js
4
4
  var i = /* @__PURE__ */ e({
5
5
  NeuralRetouch: () => m,
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./rolldown-runtime-CAFD8bLK.js";
2
- import { S as t, t as n, y as r } from "./ToneMapGPU-BVE852iN.js";
2
+ import { S as t, t as n, y as r } from "./ToneMapGPU-DpUZDMbQ.js";
3
3
  //#region src/EngineEvents.js
4
4
  var i = {
5
5
  RENDER_COMPLETE: "engine:renderComplete",
@@ -35,7 +35,8 @@ var i = {
35
35
  DISPOSE: "engine:dispose",
36
36
  DEVICE_LOST: "engine:deviceLost",
37
37
  ISSUE: "engine:issue",
38
- SCENE_METADATA_APPLIED: "engine:sceneMetadataApplied"
38
+ SCENE_METADATA_APPLIED: "engine:sceneMetadataApplied",
39
+ STORAGE_CHANGED: "engine:storageChanged"
39
40
  }, a = /* @__PURE__ */ e({
40
41
  NeuralSuperRes: () => g,
41
42
  SR_MAX_INPUT: () => c,
@@ -110,7 +110,8 @@ var D = {
110
110
  upscalerModelBaseUrl: "https://huggingface.co/notaneimu/onnx-image-models/resolve/main/",
111
111
  neuralRuntimeUrl: "/neural/neural-runtime.js",
112
112
  neuralAssetBaseUrl: null,
113
- cacheNamespace: "rayzee"
113
+ cacheNamespace: "rayzee",
114
+ storage: "auto"
114
115
  };
115
116
  function O(e) {
116
117
  e && Object.assign(D, e);