@meimu/mutracer 0.2.0 → 0.3.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 (211) hide show
  1. package/README.md +3 -0
  2. package/dist/assets/bvh.worker.js +1 -1
  3. package/dist/mutracer.umd.js +8949 -7915
  4. package/docs/api.md +42 -21
  5. package/docs/caustics.md +80 -0
  6. package/docs/materials.md +5 -4
  7. package/docs/progressive-rendering.md +50 -9
  8. package/docs/technical/continuous-spectrum.md +93 -0
  9. package/docs/updates.md +3 -1
  10. package/docs/viewer-checklist.md +65 -0
  11. package/docs/viewer.md +7 -5
  12. package/lib/Display.js +1 -1
  13. package/lib/Display.js.map +1 -1
  14. package/lib/Engine.d.ts +2 -0
  15. package/lib/Engine.js +47 -12
  16. package/lib/Engine.js.map +1 -1
  17. package/lib/Render.d.ts +61 -13
  18. package/lib/Render.js +169 -19
  19. package/lib/Render.js.map +1 -1
  20. package/lib/RenderLoop.d.ts +7 -3
  21. package/lib/RenderLoop.js +68 -44
  22. package/lib/RenderLoop.js.map +1 -1
  23. package/lib/main.d.ts +1 -1
  24. package/lib/main.js.map +1 -1
  25. package/lib/oidn.d.ts +1 -1
  26. package/lib/oidnBundledWeights.cdn.d.ts +2 -2
  27. package/lib/renderer/GPUTraceQueue.d.ts +2 -1
  28. package/lib/renderer/GPUTraceQueue.js +3 -1
  29. package/lib/renderer/GPUTraceQueue.js.map +1 -1
  30. package/lib/renderer/RenderingPipeline.d.ts +4 -0
  31. package/lib/renderer/RenderingPipeline.js.map +1 -1
  32. package/lib/renderer/WGPUCausticLightPass.d.ts +48 -0
  33. package/lib/renderer/WGPUCausticLightPass.js +217 -0
  34. package/lib/renderer/WGPUCausticLightPass.js.map +1 -0
  35. package/lib/renderer/WGPUEnvMapDistribution.js +18 -18
  36. package/lib/renderer/WGPUFullQuadPass.js +3 -3
  37. package/lib/renderer/WGPUPhotonMap.d.ts +37 -0
  38. package/lib/renderer/WGPUPhotonMap.js +191 -0
  39. package/lib/renderer/WGPUPhotonMap.js.map +1 -0
  40. package/lib/renderer/WGPURayTraceOutput.d.ts +13 -1
  41. package/lib/renderer/WGPURayTraceOutput.js +122 -28
  42. package/lib/renderer/WGPURayTraceOutput.js.map +1 -1
  43. package/lib/renderer/WGPURayTracePass.d.ts +48 -17
  44. package/lib/renderer/WGPURayTracePass.js +538 -340
  45. package/lib/renderer/WGPURayTracePass.js.map +1 -1
  46. package/lib/renderer/WGPURenderingPipeline.js +83 -47
  47. package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
  48. package/lib/renderer/WebGLFullQuadPass.d.ts +2 -1
  49. package/lib/renderer/WebGLFullQuadPass.js +4 -0
  50. package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
  51. package/lib/renderer/WebGLJNLMDenoiser.js +66 -66
  52. package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
  53. package/lib/renderer/WebGLRayTracePass.d.ts +6 -1
  54. package/lib/renderer/WebGLRayTracePass.js +43 -6
  55. package/lib/renderer/WebGLRayTracePass.js.map +1 -1
  56. package/lib/renderer/WebGLRenderingPipeline.js +10 -14
  57. package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
  58. package/lib/renderer/WebGLSkyBaker.js +60 -60
  59. package/lib/renderer/accumulationTarget.d.ts +2 -1
  60. package/lib/renderer/accumulationTarget.js.map +1 -1
  61. package/lib/renderer/causticDiagnostics.d.ts +31 -0
  62. package/lib/renderer/causticDiagnostics.js +5 -0
  63. package/lib/renderer/causticDiagnostics.js.map +1 -0
  64. package/lib/renderer/causticEmission.d.ts +10 -0
  65. package/lib/renderer/causticEmission.js +40 -0
  66. package/lib/renderer/causticEmission.js.map +1 -0
  67. package/lib/renderer/causticUniform.d.ts +12 -0
  68. package/lib/renderer/causticUniform.js +22 -0
  69. package/lib/renderer/causticUniform.js.map +1 -0
  70. package/lib/renderer/caustics.d.ts +16 -0
  71. package/lib/renderer/caustics.js +93 -0
  72. package/lib/renderer/caustics.js.map +1 -0
  73. package/lib/renderer/glsl/aovDisplay.frag.js +5 -5
  74. package/lib/renderer/glsl/aovReflectance.glsl.js +53 -53
  75. package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +1 -1
  76. package/lib/renderer/glsl/aovTrace.frag.js +33 -33
  77. package/lib/renderer/glsl/chunks/cameraRay.glsl.js +9 -9
  78. package/lib/renderer/glsl/chunks/emissiveLight.glsl.d.ts +2 -0
  79. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +35 -0
  80. package/lib/renderer/glsl/chunks/emissiveLight.glsl.js.map +1 -0
  81. package/lib/renderer/glsl/chunks/envMap.glsl.js +73 -73
  82. package/lib/renderer/glsl/chunks/intersect.glsl.js +426 -428
  83. package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
  84. package/lib/renderer/glsl/chunks/materialBuffer.glsl.d.ts +1 -0
  85. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +156 -153
  86. package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
  87. package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +771 -771
  88. package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
  89. package/lib/renderer/glsl/chunks/random.glsl.js +6 -6
  90. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.d.ts +1 -0
  91. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +68 -63
  92. package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
  93. package/lib/renderer/glsl/chunks/sampleLight.glsl.js +94 -76
  94. package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
  95. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -0
  96. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +140 -117
  97. package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
  98. package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +14 -14
  99. package/lib/renderer/glsl/chunks/sampling.glsl.js +89 -92
  100. package/lib/renderer/glsl/chunks/sampling.glsl.js.map +1 -1
  101. package/lib/renderer/glsl/chunks/sobol.glsl.js +79 -79
  102. package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
  103. package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
  104. package/lib/renderer/glsl/depthQuery.frag.js +2 -2
  105. package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +10 -10
  106. package/lib/renderer/glsl/rayTrace.frag.d.ts +1 -1
  107. package/lib/renderer/glsl/rayTrace.frag.js +260 -237
  108. package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
  109. package/lib/renderer/glsl/shadowCatcher.frag.js +26 -26
  110. package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
  111. package/lib/renderer/glsl/webglPipeline.frag.js +59 -59
  112. package/lib/renderer/lightSampling.d.ts +3 -2
  113. package/lib/renderer/lightSampling.js +14 -8
  114. package/lib/renderer/lightSampling.js.map +1 -1
  115. package/lib/renderer/progressiveScheduler.js +4 -3
  116. package/lib/renderer/progressiveScheduler.js.map +1 -1
  117. package/lib/renderer/renderPipeline.d.ts +1 -0
  118. package/lib/renderer/renderPipeline.js.map +1 -1
  119. package/lib/renderer/researchTransport.d.ts +31 -0
  120. package/lib/renderer/researchTransport.js +5 -0
  121. package/lib/renderer/researchTransport.js.map +1 -0
  122. package/lib/renderer/sceneLayoutSchema.d.ts +1 -0
  123. package/lib/renderer/sceneLayoutSchema.js +2 -2
  124. package/lib/renderer/sceneLayoutSchema.js.map +1 -1
  125. package/lib/renderer/scratchSampling.js +6 -6
  126. package/lib/renderer/spectrum.d.ts +21 -0
  127. package/lib/renderer/spectrum.js +154 -0
  128. package/lib/renderer/spectrum.js.map +1 -0
  129. package/lib/renderer/webglLightSampling.d.ts +39 -0
  130. package/lib/renderer/webglLightSampling.js +15 -0
  131. package/lib/renderer/webglLightSampling.js.map +1 -0
  132. package/lib/renderer/wgpuBindlessSource.js +3 -3
  133. package/lib/renderer/wgpuShaderSource.d.ts +7 -0
  134. package/lib/renderer/wgpuShaderSource.js +2 -0
  135. package/lib/renderer/wgpuShaderSource.js.map +1 -1
  136. package/lib/renderer/wgsl/aovDisplay.wgsl.js +9 -9
  137. package/lib/renderer/wgsl/aovReflectance.wgsl.js +55 -55
  138. package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +1 -1
  139. package/lib/renderer/wgsl/aovResolve.wgsl.js +2 -2
  140. package/lib/renderer/wgsl/aovSnapshot.wgsl.js +1 -1
  141. package/lib/renderer/wgsl/aovTrace.wgsl.js +33 -33
  142. package/lib/renderer/wgsl/bloom.wgsl.js +18 -18
  143. package/lib/renderer/wgsl/causticLight.compute.d.ts +6 -0
  144. package/lib/renderer/wgsl/causticLight.compute.js +537 -0
  145. package/lib/renderer/wgsl/causticLight.compute.js.map +1 -0
  146. package/lib/renderer/wgsl/chunks/background.wgsl.d.ts +2 -0
  147. package/lib/renderer/wgsl/chunks/background.wgsl.js +102 -0
  148. package/lib/renderer/wgsl/chunks/background.wgsl.js.map +1 -0
  149. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.d.ts +2 -0
  150. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +12 -0
  151. package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js.map +1 -0
  152. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.d.ts +2 -0
  153. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +16 -0
  154. package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js.map +1 -0
  155. package/lib/renderer/wgsl/chunks/caustics.wgsl.d.ts +1 -0
  156. package/lib/renderer/wgsl/chunks/caustics.wgsl.js +62 -0
  157. package/lib/renderer/wgsl/chunks/caustics.wgsl.js.map +1 -0
  158. package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
  159. package/lib/renderer/wgsl/chunks/envMap.wgsl.js +37 -37
  160. package/lib/renderer/wgsl/chunks/intersect.wgsl.js +598 -592
  161. package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
  162. package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +14 -14
  163. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +2 -1
  164. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +75 -73
  165. package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
  166. package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +794 -794
  167. package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +139 -139
  168. package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
  169. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +2 -1
  170. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +35 -25
  171. package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
  172. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.d.ts +1 -1
  173. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +142 -138
  174. package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js.map +1 -1
  175. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
  176. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +204 -187
  177. package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
  178. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.d.ts +1 -1
  179. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +11 -11
  180. package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js.map +1 -1
  181. package/lib/renderer/wgsl/chunks/sampling.wgsl.d.ts +1 -1
  182. package/lib/renderer/wgsl/chunks/sampling.wgsl.js +89 -93
  183. package/lib/renderer/wgsl/chunks/sampling.wgsl.js.map +1 -1
  184. package/lib/renderer/wgsl/chunks/sobol.wgsl.js +83 -83
  185. package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
  186. package/lib/renderer/wgsl/compose.frag.wgsl.js +98 -98
  187. package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
  188. package/lib/renderer/wgsl/depthQuery.wgsl.js +2 -2
  189. package/lib/renderer/wgsl/jnlm.compute.js +74 -74
  190. package/lib/renderer/wgsl/offlineAdaptive.compute.js +25 -25
  191. package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +3 -3
  192. package/lib/renderer/wgsl/photonMap.compute.d.ts +29 -0
  193. package/lib/renderer/wgsl/photonMap.compute.js +352 -0
  194. package/lib/renderer/wgsl/photonMap.compute.js.map +1 -0
  195. package/lib/renderer/wgsl/proceduralSky.compute.js +64 -64
  196. package/lib/renderer/wgsl/rayTrace.compute.d.ts +9 -1
  197. package/lib/renderer/wgsl/rayTrace.compute.js +448 -522
  198. package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
  199. package/lib/scene/MaterialState.d.ts +2 -2
  200. package/lib/scene/MaterialState.js +2 -2
  201. package/lib/scene/MaterialState.js.map +1 -1
  202. package/lib/settings/render.d.ts +11 -0
  203. package/lib/settings/render.js +1 -0
  204. package/lib/settings/render.js.map +1 -1
  205. package/lib/util/fromTHREE.js +2 -2
  206. package/lib/util/fromTHREE.js.map +1 -1
  207. package/lib/version.d.ts +1 -1
  208. package/lib/version.js +1 -1
  209. package/lib/version.js.map +1 -1
  210. package/llms.txt +2 -1
  211. package/package.json +3 -3
package/lib/RenderLoop.js CHANGED
@@ -2,6 +2,7 @@ import { scheduleFrame } from './util/frame.js';
2
2
  import Render from './Render.js';
3
3
  import { Events } from './util/events.js';
4
4
  import { aovChannel, updateProgressiveState, loopImageState } from './renderer/progressiveScheduler.js';
5
+ const MAX_INFERENCE_HOLD_MS = 5000;
5
6
  /** Built-in interactive policy implemented entirely through the first-layer API. */
6
7
  export default class RenderLoop {
7
8
  engine;
@@ -22,12 +23,14 @@ export default class RenderLoop {
22
23
  _busy = false;
23
24
  _disposed = false;
24
25
  _cancelScheduled;
25
- _refillGeneration = 0;
26
+ _refillController;
26
27
  _cancelRefillFrame;
27
28
  _warnedTick = false;
28
29
  /** Render whose next presentation is waiting for a complete preview frame. */
29
30
  _previewFrameOwner;
30
31
  _presented;
32
+ _inferenceHoldStart;
33
+ _lastError;
31
34
  _finishedImage;
32
35
  _motion;
33
36
  _unsubscribe;
@@ -59,8 +62,11 @@ export default class RenderLoop {
59
62
  for (const sync of syncs)
60
63
  this.addSync(sync);
61
64
  this._unsubscribe = this.final.on('sample', event => this._events.emit('sample', { ...event, preview: false }));
62
- if (typeof document !== 'undefined')
65
+ if (typeof document !== 'undefined') {
63
66
  document.addEventListener('visibilitychange', this._visibility);
67
+ for (const event of this._inputEvents)
68
+ document.addEventListener(event, this._input, { capture: true, passive: true });
69
+ }
64
70
  }
65
71
  _render(value, defaults) {
66
72
  if (value instanceof Render)
@@ -83,6 +89,7 @@ export default class RenderLoop {
83
89
  /** Whether an explicit integration or consecutive edits indicate motion. Default false. */ get changing() { return this._changing; }
84
90
  /** Complete final beauty samples; preview and AOV-only sampling are excluded. Default 0. */ get samples() { return this.status === 'previewing' ? 0 : this.final.samples; }
85
91
  /** Current presented/execution state. Default preparing. */ get status() { return this._status; }
92
+ /** Exception thrown by the latest tick, such as from a sync or scene update; status is error while set. Default undefined. */ get lastError() { return this._lastError; }
86
93
  /** Subscribes to status transitions or complete final samples; returns unsubscribe. */
87
94
  on(event, listener) { return this._events.on(event, listener); }
88
95
  /** Adds an integration on this engine. Duplicate registrations are ignored. */
@@ -114,9 +121,27 @@ export default class RenderLoop {
114
121
  }
115
122
  return this._tick();
116
123
  }
124
+ // Anything thrown here would otherwise repeat every frame while status keeps
125
+ // reporting the last healthy state.
117
126
  _tick() {
127
+ try {
128
+ const status = this._runTick();
129
+ this._lastError = undefined;
130
+ return status;
131
+ }
132
+ catch (value) {
133
+ const error = value instanceof Error ? value : new Error(String(value));
134
+ if (error.message !== this._lastError?.message)
135
+ console.error(`RenderLoop tick failed: ${error.message}`, error);
136
+ this._lastError = error;
137
+ this._cancelRefill();
138
+ this._previewFrameOwner = undefined;
139
+ return this._setStatus('error');
140
+ }
141
+ }
142
+ _runTick() {
118
143
  this._cancelRefill();
119
- const refillGeneration = this._refillGeneration;
144
+ const controller = this._refillController = new AbortController();
120
145
  if (this._busy || (typeof document !== 'undefined' && document.hidden))
121
146
  return this.status;
122
147
  for (const sync of this._syncs)
@@ -130,7 +155,13 @@ export default class RenderLoop {
130
155
  const owner = this._previewFrameOwner;
131
156
  const pendingPreview = !!owner && (owner === this.preview || !owner._completeFor(this.display.channel));
132
157
  const tracingPreview = pendingPreview && this.preview?.status === 'converging' && samples(this.preview) === 0;
133
- const holding = tracingPreview || (!aov && this.coalesceSceneUpdates && pendingPreview && !!this.preview?.denoising);
158
+ const holdingInference = !aov && this.coalesceSceneUpdates && pendingPreview && !!this.preview?.denoising;
159
+ if (!holdingInference)
160
+ this._inferenceHoldStart = undefined;
161
+ else
162
+ this._inferenceHoldStart ??= performance.now();
163
+ // Only a commit can cancel inference, so a stalled filter must not hold it forever.
164
+ const holding = tracingPreview || (holdingInference && performance.now() - this._inferenceHoldStart < MAX_INFERENCE_HOLD_MS);
134
165
  // Inference belongs to a presentation, not merely to a background render.
135
166
  // A fallback result must never replace an already available final image.
136
167
  if (pendingPreview && !holding && this.preview)
@@ -181,7 +212,23 @@ export default class RenderLoop {
181
212
  current._restartAovs();
182
213
  motion.phase = 'settling';
183
214
  }
184
- let status = refine(current);
215
+ const refill = !aov && idle && current === this.final;
216
+ let status;
217
+ if (refill) {
218
+ // Keep the loop's short synchronous budget; the public helper uses an
219
+ // ordinary refine(). Selection/activity are application policy, revoked
220
+ // through the same signal as input, stop and the next display frame.
221
+ void current._refineUntil(performance.now() + 1000 / 60, controller.signal, { batchSamples: current.batchSamples, targetBatchTimeMs: 4 }, () => {
222
+ if ([...this._syncs].some(sync => sync.active) || this.select({ changing: false }) !== 'final')
223
+ controller.abort();
224
+ }).then(() => {
225
+ if (!controller.signal.aborted && current.status === 'error')
226
+ this._setStatus('error');
227
+ });
228
+ status = current.status;
229
+ }
230
+ else
231
+ status = refine(current);
185
232
  if (motion?.phase === 'priming' && status === 'finished') {
186
233
  current._restartAovs();
187
234
  motion.phase = 'settling';
@@ -202,50 +249,20 @@ export default class RenderLoop {
202
249
  const previewing = waitingForPreview || (!aov && current === this.preview && current.denoising) || (!!this.preview && this._presented === this.preview);
203
250
  const next = status === 'error' ? 'error' : previewing ? 'previewing' : status;
204
251
  this._finishedImage = next === 'finished' ? loopImageState(this.final, this.display) : undefined;
205
- if (refillGeneration === this._refillGeneration && !aov && idle && current === this.final && !previewing)
206
- this._scheduleRefill();
252
+ if (refill && !previewing && !controller.signal.aborted && current._refilling) {
253
+ // Manual tick grants work only until the next display frame.
254
+ this._cancelRefillFrame = scheduleFrame(() => this._cancelRefill());
255
+ }
256
+ else
257
+ controller.abort();
207
258
  return this._setStatus(next);
208
259
  }
209
260
  _cancelRefill() {
210
- this._refillGeneration++;
261
+ this._refillController?.abort();
262
+ this._refillController = undefined;
211
263
  this._cancelRefillFrame?.();
212
264
  this._cancelRefillFrame = undefined;
213
265
  }
214
- _scheduleRefill() {
215
- const device = this.engine.device;
216
- if (!device || !this._canRefill())
217
- return;
218
- const generation = this._refillGeneration;
219
- // A manual tick grants work only until the next display frame. If the host
220
- // stops ticking (pause/export), it cannot leave a background render running.
221
- this._cancelRefillFrame = scheduleFrame(() => this._cancelRefill());
222
- const refill = () => {
223
- if (generation !== this._refillGeneration || device !== this.engine.device ||
224
- this._disposed || this._busy || (typeof document !== 'undefined' && document.hidden) ||
225
- aovChannel(this.display.channel) ||
226
- !this._canRefill() || [...this._syncs].some(sync => sync.active) ||
227
- this.select({ changing: false }) !== 'final')
228
- return;
229
- const before = this.final.samples;
230
- const status = this.final.refine(undefined, { targetBatchTimeMs: 4, deferResolve: true });
231
- if (status === 'error') {
232
- this._cancelRefill();
233
- this._setStatus('error');
234
- return;
235
- }
236
- if (this.final.samples > before && status === 'converging')
237
- wait();
238
- };
239
- const wait = () => { void this.final.whenReadyToRefine().then(refill, () => { }); };
240
- // Keep only a short chunk ahead of input. GPU completion, rather than the
241
- // display refresh rate, paces the next chunk; presentation stays on rAF.
242
- wait();
243
- }
244
- _canRefill() {
245
- const time = this.final.gpuSampleTimeMs;
246
- return this.final.batchSamples && !this.final.denoising && this.final.samples > 0 &&
247
- this.final.status === 'converging' && time !== undefined && time <= this.final.timeBudgetMs;
248
- }
249
266
  _schedule() {
250
267
  if (!this._running || this._busy || this._cancelScheduled !== undefined || (typeof document !== 'undefined' && document.hidden))
251
268
  return;
@@ -256,6 +273,10 @@ export default class RenderLoop {
256
273
  this._schedule();
257
274
  } });
258
275
  }
276
+ // Input may finish before the next sync update (for example a quick drag).
277
+ // Revoke the old frame's lease at dispatch, before a GPU fence can refill it.
278
+ _inputEvents = ['pointerdown', 'pointermove', 'pointerup', 'wheel', 'keydown', 'input', 'change'];
279
+ _input = () => { this._cancelRefill(); };
259
280
  _visibility = () => {
260
281
  if (document.hidden) {
261
282
  this._cancelFrame();
@@ -307,8 +328,11 @@ export default class RenderLoop {
307
328
  this._unsubscribe();
308
329
  this._events.clear();
309
330
  this._syncs.clear();
310
- if (typeof document !== 'undefined')
331
+ if (typeof document !== 'undefined') {
311
332
  document.removeEventListener('visibilitychange', this._visibility);
333
+ for (const event of this._inputEvents)
334
+ document.removeEventListener(event, this._input, true);
335
+ }
312
336
  for (const render of this._owned)
313
337
  render.dispose();
314
338
  this._owned.clear();
@@ -1 +1 @@
1
- {"version":3,"file":"RenderLoop.js","sourceRoot":"","sources":["../src/RenderLoop.ts"],"names":[],"mappings":"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","sourcesContent":["import {scheduleFrame} from './util/frame.js';\nimport type Engine from './Engine.js';\nimport type Display from './Display.js';\nimport Render, { type RenderOptions, type RenderStatus, type ConvergeOptions, type ConvergeResult, type SampleEvent } from './Render.js';\nimport type Sync from './Sync.js';\nimport { Events } from './util/events.js';\nimport { aovChannel, updateProgressiveState, loopImageState, type ProgressiveState } from './renderer/progressiveScheduler.js';\n\n/** Presentation state; preview images never count as final completion. */\nexport type RenderLoopStatus = RenderStatus | 'previewing';\nexport interface RenderLoopOptions {\n /** Presentation settings/canvas. Default engine.display. */ display?: Display;\n /** Preview render/settings, or false to disable. Default half resolution with adaptive scale .125–.5, 80 ms budget, 2 bounces, no bevel, 1 wavelength and 2 light candidates. */ preview?: Render | RenderOptions | false;\n /** Final render/settings. Default a new Render with preview as fallback. */ final?: Render | RenderOptions;\n /** External integrations, invoked in order. Default none. */ sync?: Sync | Sync[];\n /** Idle delay for consecutive edits without explicit sync activity. Default 150 ms. */ idleMs?: number;\n /** Hold preview inference before committing the latest camera/scene. Default false. */ coalesceSceneUpdates?: boolean;\n}\ninterface LoopEvents {\n status: {status: RenderLoopStatus; previous: RenderLoopStatus};\n sample: SampleEvent & {preview: false};\n}\n\n/** Built-in interactive policy implemented entirely through the first-layer API. */\nexport default class RenderLoop {\n readonly preview: Render | undefined;\n readonly final: Render;\n readonly display: Display;\n /** Selection policy. Default changing ? preview : final; absent previews select final. */\n select: (info: {changing: boolean}) => 'preview' | 'final' = ({changing}) => changing ? 'preview' : 'final';\n /** Heuristic idle delay. Default 150 ms. */ idleMs: number;\n /** Defer engine commits while preview inference is pending. Default false. */ coalesceSceneUpdates: boolean;\n private _changing = false;\n private _status: RenderLoopStatus = 'preparing';\n private _events = new Events<LoopEvents>();\n private _syncs = new Set<Sync>();\n private _owned = new Set<Render>();\n private _policy: ProgressiveState = {previousChanged: false, lastContinuousChange: -Infinity, changing: false};\n private _running = false;\n private _busy = false;\n private _disposed = false;\n private _cancelScheduled?: () => void;\n private _refillGeneration = 0;\n private _cancelRefillFrame?: () => void;\n private _warnedTick = false;\n /** Render whose next presentation is waiting for a complete preview frame. */\n private _previewFrameOwner?: Render;\n private _presented?: Render;\n private _finishedImage?: string;\n private _motion?: {render: Render; phase: 'moving' | 'priming' | 'settling' | 'settled'};\n private _unsubscribe: () => void;\n constructor(readonly engine: Engine, options: RenderLoopOptions = {}) {\n // Validate foreign objects before allocating owned resources.\n const syncs = options.sync ? (Array.isArray(options.sync) ? options.sync : [options.sync]) : [];\n for (const sync of syncs) this._checkEngine(sync.engine);\n for (const render of [options.preview, options.final]) if (render instanceof Render) this._checkEngine(render.engine);\n this.display = options.display ?? engine.display;\n this.idleMs = options.idleMs ?? 150;\n this.coalesceSceneUpdates = options.coalesceSceneUpdates ?? false;\n try {\n if (options.preview !== false) this.preview = this._render(options.preview, {\n resolutionScale: .5, timeBudgetMs: 80, adaptiveResolution: {targetFrameMs: 80, minScale: .125},\n bounces: 2, bevel: false, dispersionWavelengths: 1, directLightCandidates: 2,\n });\n this.final = this._render(options.final, {fallback: this.preview ?? null});\n } catch (error) {for (const render of this._owned) render.dispose(); throw error;}\n for (const sync of syncs) this.addSync(sync);\n this._unsubscribe = this.final.on('sample', event => this._events.emit('sample', {...event, preview: false}));\n if (typeof document !== 'undefined') document.addEventListener('visibilitychange', this._visibility);\n }\n private _render(value: Render | RenderOptions | undefined, defaults: RenderOptions): Render {\n if (value instanceof Render) return value;\n const settings = {...defaults, ...value};\n if (value && 'width' in value) {\n if (!('resolutionScale' in value)) delete settings.resolutionScale;\n if (!('adaptiveResolution' in value)) delete settings.adaptiveResolution;\n }\n const render = new Render(this.engine, settings as RenderOptions); this._owned.add(render); return render;\n }\n private _checkEngine(engine: Engine): void { if (engine !== this.engine) throw new Error('RenderLoop renders and syncs must belong to the same engine.'); }\n private _assertAlive(): void { if (this._disposed) throw new Error('RenderLoop is disposed.'); }\n /** Whether an explicit integration or consecutive edits indicate motion. Default false. */ get changing(): boolean { return this._changing; }\n /** Complete final beauty samples; preview and AOV-only sampling are excluded. Default 0. */ get samples(): number { return this.status === 'previewing' ? 0 : this.final.samples; }\n /** Current presented/execution state. Default preparing. */ get status(): RenderLoopStatus { return this._status; }\n /** Subscribes to status transitions or complete final samples; returns unsubscribe. */\n on<K extends keyof LoopEvents>(event: K, listener: (value: LoopEvents[K]) => void): () => void { return this._events.on(event, listener); }\n /** Adds an integration on this engine. Duplicate registrations are ignored. */\n addSync(sync: Sync): void { this._assertAlive(); this._checkEngine(sync.engine); this._syncs.add(sync); }\n /** Removes an integration without disposing it. */ removeSync(sync: Sync): void { this._syncs.delete(sync); }\n private _setStatus(status: RenderLoopStatus): RenderLoopStatus {\n if (status !== this._status) { const previous = this._status; this._status = status; this._events.emit('status', {status, previous}); }\n return status;\n }\n private _present(render: Render): Render | undefined {\n const shown = this.display.present(render);\n if (shown) this._presented = shown;\n return shown;\n }\n /** Executes one manual tick. Calls during start are ignored with one warning. */\n tick(): RenderLoopStatus {\n this._assertAlive();\n if (this._running) { if (!this._warnedTick) {this._warnedTick = true; console.warn('RenderLoop.tick() is ignored while start() is active.');} return this.status; }\n return this._tick();\n }\n private _tick(): RenderLoopStatus {\n this._cancelRefill();\n const refillGeneration = this._refillGeneration;\n if (this._busy || (typeof document !== 'undefined' && document.hidden)) return this.status;\n for (const sync of this._syncs) sync.update();\n const aov = aovChannel(this.display.channel);\n const refine = (render: Render) => render.refine(aov, {\n batchSamples: render.batchSamples && !this.changing && render !== this.preview,\n targetBatchTimeMs: 4,\n });\n const samples = (render: Render) => aov ? render.aovSamplesRendered : render.samples;\n const owner = this._previewFrameOwner;\n const pendingPreview = !!owner && (owner === this.preview || !owner._completeFor(this.display.channel));\n const tracingPreview = pendingPreview && this.preview?.status === 'converging' && samples(this.preview) === 0;\n const holding = tracingPreview || (!aov && this.coalesceSceneUpdates && pendingPreview && !!this.preview?.denoising);\n // Inference belongs to a presentation, not merely to a background render.\n // A fallback result must never replace an already available final image.\n if (pendingPreview && !holding && this.preview) this._present(this.preview);\n if (!holding) this._previewFrameOwner = undefined;\n const changed = holding ? false : this.engine.update();\n const active = [...this._syncs].some(sync => sync.active);\n this._policy = updateProgressiveState(this._policy, changed, active, performance.now(), this.idleMs);\n this._changing = this._policy.changing;\n const selected = this.select({changing: this.changing});\n if (holding && this.preview) {\n // Finish this image against its committed camera while syncs collect the\n // latest input. Restarting its first tile on every edit starves presentation.\n if (tracingPreview) {\n const status = refine(this.preview);\n if (status === 'error') { this._previewFrameOwner = undefined; return this._setStatus('error'); }\n if ((!this.coalesceSceneUpdates || !this.preview.denoising) && this._present(this.preview)) this._previewFrameOwner = undefined;\n }\n return this._setStatus('previewing');\n }\n const current = selected === 'preview' && this.preview ? this.preview : this.final;\n const idle = !changed && !this.changing;\n if (aov !== 'motion') this._motion = undefined;\n else if (this._motion?.render !== current) {\n // Targets have independent histories. Prime every target switch, even\n // when a final small camera edit coincides with leaving preview.\n this._motion = {render: current, phase: this._motion ? 'priming' : 'moving'};\n } else if ((!idle && this._motion.phase !== 'priming') || (!current._completeFor('motion') && this._motion.phase === 'settled')) {\n this._motion.phase = 'moving';\n }\n const motion = this._motion;\n const imageState = loopImageState(this.final, this.display);\n if (idle && current === this.final && this.status === 'finished' && this.final.status === 'finished' && imageState === this._finishedImage && (!motion || motion.phase === 'settled')) return this.status;\n // Invalidate a completed filter before refinement when display settings changed.\n if (this.status === 'finished' && imageState !== this._finishedImage && this.final.samples > 0) this._present(this.final);\n // Motion describes successive images. One unchanged image retires the last\n // displacement; afterwards leave the finished target idle as usual.\n if (motion?.phase === 'moving' && idle && current._completeFor('motion')) {\n current._restartAovs(); motion.phase = 'settling';\n }\n let status = refine(current);\n if (motion?.phase === 'priming' && status === 'finished') {\n current._restartAovs(); motion.phase = 'settling'; status = refine(current);\n }\n if (motion?.phase === 'settling' && status === 'finished') motion.phase = 'settled';\n // Keep the canvas on the last completed image while filtering the next\n // preview; presenting its raw sample here would overwrite the denoise above.\n const waitingForPreview = !!this.preview && ((current === this.preview && status === 'converging' && samples(current) === 0) || (!aov && this.coalesceSceneUpdates && this.preview.denoising)) &&\n (current === this.preview || (!current._completeFor(this.display.channel) && current.fallback === this.preview));\n if (waitingForPreview) this._previewFrameOwner = current;\n else this._present(current);\n // Execution may already be tracing final tiles while the canvas still shows\n // preview. Only a successful presentation transfers ownership of the image.\n const previewing = waitingForPreview || (!aov && current === this.preview && current.denoising) || (!!this.preview && this._presented === this.preview);\n const next = status === 'error' ? 'error' : previewing ? 'previewing' : status;\n this._finishedImage = next === 'finished' ? loopImageState(this.final, this.display) : undefined;\n if (refillGeneration === this._refillGeneration && !aov && idle && current === this.final && !previewing) this._scheduleRefill();\n return this._setStatus(next);\n }\n private _cancelRefill(): void {\n this._refillGeneration++;\n this._cancelRefillFrame?.(); this._cancelRefillFrame = undefined;\n }\n private _scheduleRefill(): void {\n const device = this.engine.device;\n if (!device || !this._canRefill()) return;\n const generation = this._refillGeneration;\n // A manual tick grants work only until the next display frame. If the host\n // stops ticking (pause/export), it cannot leave a background render running.\n this._cancelRefillFrame = scheduleFrame(() => this._cancelRefill());\n const refill = () => {\n if (generation !== this._refillGeneration || device !== this.engine.device ||\n this._disposed || this._busy || (typeof document !== 'undefined' && document.hidden) ||\n aovChannel(this.display.channel) ||\n !this._canRefill() || [...this._syncs].some(sync => sync.active) ||\n this.select({changing: false}) !== 'final') return;\n const before = this.final.samples;\n const status = this.final.refine(undefined, {targetBatchTimeMs: 4, deferResolve: true});\n if (status === 'error') {this._cancelRefill(); this._setStatus('error'); return;}\n if (this.final.samples > before && status === 'converging') wait();\n };\n const wait = () => {void this.final.whenReadyToRefine().then(refill, () => {});};\n // Keep only a short chunk ahead of input. GPU completion, rather than the\n // display refresh rate, paces the next chunk; presentation stays on rAF.\n wait();\n }\n private _canRefill(): boolean {\n const time = this.final.gpuSampleTimeMs;\n return this.final.batchSamples && !this.final.denoising && this.final.samples > 0 &&\n this.final.status === 'converging' && time !== undefined && time <= this.final.timeBudgetMs;\n }\n private _schedule(): void {\n if (!this._running || this._busy || this._cancelScheduled !== undefined || (typeof document !== 'undefined' && document.hidden)) return;\n this._cancelScheduled = scheduleFrame(() => { this._cancelScheduled = undefined; try {this._tick();} finally {this._schedule();} });\n }\n private _visibility = (): void => {\n if (document.hidden) {this._cancelFrame(); this._cancelRefill();} else this._schedule();\n };\n private _cancelFrame(): void { this._cancelScheduled?.(); this._cancelScheduled = undefined; }\n /** Starts an idempotent loop; uses a 16 ms timer without rAF. Hidden pages pause automatically. */ start(): void { this._assertAlive(); this._running = true; this._schedule(); }\n /** Stops scheduling without discarding accumulated images. */ stop(): void { this._running = false; this._cancelFrame(); this._cancelRefill(); }\n /** Pauses ticks, converges final, presents it, and resumes a previously running loop. */\n async converge(options: ConvergeOptions): Promise<ConvergeResult> {\n this._assertAlive(); if (this._busy) throw new Error('RenderLoop convergence is already running.');\n this._busy = true; this._previewFrameOwner = undefined; this._cancelFrame(); this._cancelRefill();\n try {\n for (const sync of this._syncs) sync.update(); this.engine.update();\n this._setStatus('preparing');\n const result = await this.final.converge({...options, onProgress: progress => {\n this._setStatus(progress.stage === 'denoising' ? 'denoising' : this.final.status);\n options.onProgress?.(progress);\n }});\n this._present(this.final); this._setStatus('finished'); return result;\n } catch (error) {this._setStatus('error'); throw error;}\n finally {this._busy = false; this._schedule();}\n }\n /** Stops the loop and releases renders it created. Supplied renders/syncs remain owned by the caller. */\n dispose(): void {\n if (this._disposed) return;\n this.stop(); this._disposed = true; this._unsubscribe(); this._events.clear(); this._syncs.clear();\n if (typeof document !== 'undefined') document.removeEventListener('visibilitychange', this._visibility);\n for (const render of this._owned) render.dispose(); this._owned.clear();\n }\n}\n"]}
1
+ {"version":3,"file":"RenderLoop.js","sourceRoot":"","sources":["../src/RenderLoop.ts"],"names":[],"mappings":"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","sourcesContent":["import {scheduleFrame} from './util/frame.js';\nimport type Engine from './Engine.js';\nimport type Display from './Display.js';\nimport Render, { type RenderOptions, type RenderStatus, type ConvergeOptions, type ConvergeResult, type SampleEvent } from './Render.js';\nimport type Sync from './Sync.js';\nimport { Events } from './util/events.js';\nimport { aovChannel, updateProgressiveState, loopImageState, type ProgressiveState } from './renderer/progressiveScheduler.js';\n\nconst MAX_INFERENCE_HOLD_MS = 5000;\n\n/** Presentation state; preview images never count as final completion. */\nexport type RenderLoopStatus = RenderStatus | 'previewing';\nexport interface RenderLoopOptions {\n /** Presentation settings/canvas. Default engine.display. */ display?: Display;\n /** Preview render/settings, or false to disable. Default half resolution with adaptive scale .125–.5, 80 ms budget, 2 bounces, no bevel, 1 wavelength and 2 light candidates. */ preview?: Render | RenderOptions | false;\n /** Final render/settings. Default a new Render with preview as fallback. */ final?: Render | RenderOptions;\n /** External integrations, invoked in order. Default none. */ sync?: Sync | Sync[];\n /** Idle delay for consecutive edits without explicit sync activity. Default 150 ms. */ idleMs?: number;\n /** Hold preview inference before committing the latest camera/scene. Default false. */ coalesceSceneUpdates?: boolean;\n}\ninterface LoopEvents {\n status: {status: RenderLoopStatus; previous: RenderLoopStatus};\n sample: SampleEvent & {preview: false};\n}\n\n/** Built-in interactive policy implemented entirely through the first-layer API. */\nexport default class RenderLoop {\n readonly preview: Render | undefined;\n readonly final: Render;\n readonly display: Display;\n /** Selection policy. Default changing ? preview : final; absent previews select final. */\n select: (info: {changing: boolean}) => 'preview' | 'final' = ({changing}) => changing ? 'preview' : 'final';\n /** Heuristic idle delay. Default 150 ms. */ idleMs: number;\n /** Defer engine commits while preview inference is pending. Default false. */ coalesceSceneUpdates: boolean;\n private _changing = false;\n private _status: RenderLoopStatus = 'preparing';\n private _events = new Events<LoopEvents>();\n private _syncs = new Set<Sync>();\n private _owned = new Set<Render>();\n private _policy: ProgressiveState = {previousChanged: false, lastContinuousChange: -Infinity, changing: false};\n private _running = false;\n private _busy = false;\n private _disposed = false;\n private _cancelScheduled?: () => void;\n private _refillController?: AbortController;\n private _cancelRefillFrame?: () => void;\n private _warnedTick = false;\n /** Render whose next presentation is waiting for a complete preview frame. */\n private _previewFrameOwner?: Render;\n private _presented?: Render;\n private _inferenceHoldStart?: number;\n private _lastError?: Error;\n private _finishedImage?: string;\n private _motion?: {render: Render; phase: 'moving' | 'priming' | 'settling' | 'settled'};\n private _unsubscribe: () => void;\n constructor(readonly engine: Engine, options: RenderLoopOptions = {}) {\n // Validate foreign objects before allocating owned resources.\n const syncs = options.sync ? (Array.isArray(options.sync) ? options.sync : [options.sync]) : [];\n for (const sync of syncs) this._checkEngine(sync.engine);\n for (const render of [options.preview, options.final]) if (render instanceof Render) this._checkEngine(render.engine);\n this.display = options.display ?? engine.display;\n this.idleMs = options.idleMs ?? 150;\n this.coalesceSceneUpdates = options.coalesceSceneUpdates ?? false;\n try {\n if (options.preview !== false) this.preview = this._render(options.preview, {\n resolutionScale: .5, timeBudgetMs: 80, adaptiveResolution: {targetFrameMs: 80, minScale: .125},\n bounces: 2, bevel: false, dispersionWavelengths: 1, directLightCandidates: 2,\n });\n this.final = this._render(options.final, {fallback: this.preview ?? null});\n } catch (error) {for (const render of this._owned) render.dispose(); throw error;}\n for (const sync of syncs) this.addSync(sync);\n this._unsubscribe = this.final.on('sample', event => this._events.emit('sample', {...event, preview: false}));\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', this._visibility);\n for (const event of this._inputEvents) document.addEventListener(event, this._input, {capture: true, passive: true});\n }\n }\n private _render(value: Render | RenderOptions | undefined, defaults: RenderOptions): Render {\n if (value instanceof Render) return value;\n const settings = {...defaults, ...value};\n if (value && 'width' in value) {\n if (!('resolutionScale' in value)) delete settings.resolutionScale;\n if (!('adaptiveResolution' in value)) delete settings.adaptiveResolution;\n }\n const render = new Render(this.engine, settings as RenderOptions); this._owned.add(render); return render;\n }\n private _checkEngine(engine: Engine): void { if (engine !== this.engine) throw new Error('RenderLoop renders and syncs must belong to the same engine.'); }\n private _assertAlive(): void { if (this._disposed) throw new Error('RenderLoop is disposed.'); }\n /** Whether an explicit integration or consecutive edits indicate motion. Default false. */ get changing(): boolean { return this._changing; }\n /** Complete final beauty samples; preview and AOV-only sampling are excluded. Default 0. */ get samples(): number { return this.status === 'previewing' ? 0 : this.final.samples; }\n /** Current presented/execution state. Default preparing. */ get status(): RenderLoopStatus { return this._status; }\n /** Exception thrown by the latest tick, such as from a sync or scene update; status is error while set. Default undefined. */ get lastError(): Error | undefined { return this._lastError; }\n /** Subscribes to status transitions or complete final samples; returns unsubscribe. */\n on<K extends keyof LoopEvents>(event: K, listener: (value: LoopEvents[K]) => void): () => void { return this._events.on(event, listener); }\n /** Adds an integration on this engine. Duplicate registrations are ignored. */\n addSync(sync: Sync): void { this._assertAlive(); this._checkEngine(sync.engine); this._syncs.add(sync); }\n /** Removes an integration without disposing it. */ removeSync(sync: Sync): void { this._syncs.delete(sync); }\n private _setStatus(status: RenderLoopStatus): RenderLoopStatus {\n if (status !== this._status) { const previous = this._status; this._status = status; this._events.emit('status', {status, previous}); }\n return status;\n }\n private _present(render: Render): Render | undefined {\n const shown = this.display.present(render);\n if (shown) this._presented = shown;\n return shown;\n }\n /** Executes one manual tick. Calls during start are ignored with one warning. */\n tick(): RenderLoopStatus {\n this._assertAlive();\n if (this._running) { if (!this._warnedTick) {this._warnedTick = true; console.warn('RenderLoop.tick() is ignored while start() is active.');} return this.status; }\n return this._tick();\n }\n // Anything thrown here would otherwise repeat every frame while status keeps\n // reporting the last healthy state.\n private _tick(): RenderLoopStatus {\n try {\n const status = this._runTick();\n this._lastError = undefined;\n return status;\n } catch (value) {\n const error = value instanceof Error ? value : new Error(String(value));\n if (error.message !== this._lastError?.message) console.error(`RenderLoop tick failed: ${error.message}`, error);\n this._lastError = error;\n this._cancelRefill(); this._previewFrameOwner = undefined;\n return this._setStatus('error');\n }\n }\n private _runTick(): RenderLoopStatus {\n this._cancelRefill();\n const controller = this._refillController = new AbortController();\n if (this._busy || (typeof document !== 'undefined' && document.hidden)) return this.status;\n for (const sync of this._syncs) sync.update();\n const aov = aovChannel(this.display.channel);\n const refine = (render: Render) => render.refine(aov, {\n batchSamples: render.batchSamples && !this.changing && render !== this.preview,\n targetBatchTimeMs: 4,\n });\n const samples = (render: Render) => aov ? render.aovSamplesRendered : render.samples;\n const owner = this._previewFrameOwner;\n const pendingPreview = !!owner && (owner === this.preview || !owner._completeFor(this.display.channel));\n const tracingPreview = pendingPreview && this.preview?.status === 'converging' && samples(this.preview) === 0;\n const holdingInference = !aov && this.coalesceSceneUpdates && pendingPreview && !!this.preview?.denoising;\n if (!holdingInference) this._inferenceHoldStart = undefined;\n else this._inferenceHoldStart ??= performance.now();\n // Only a commit can cancel inference, so a stalled filter must not hold it forever.\n const holding = tracingPreview || (holdingInference && performance.now() - this._inferenceHoldStart! < MAX_INFERENCE_HOLD_MS);\n // Inference belongs to a presentation, not merely to a background render.\n // A fallback result must never replace an already available final image.\n if (pendingPreview && !holding && this.preview) this._present(this.preview);\n if (!holding) this._previewFrameOwner = undefined;\n const changed = holding ? false : this.engine.update();\n const active = [...this._syncs].some(sync => sync.active);\n this._policy = updateProgressiveState(this._policy, changed, active, performance.now(), this.idleMs);\n this._changing = this._policy.changing;\n const selected = this.select({changing: this.changing});\n if (holding && this.preview) {\n // Finish this image against its committed camera while syncs collect the\n // latest input. Restarting its first tile on every edit starves presentation.\n if (tracingPreview) {\n const status = refine(this.preview);\n if (status === 'error') { this._previewFrameOwner = undefined; return this._setStatus('error'); }\n if ((!this.coalesceSceneUpdates || !this.preview.denoising) && this._present(this.preview)) this._previewFrameOwner = undefined;\n }\n return this._setStatus('previewing');\n }\n const current = selected === 'preview' && this.preview ? this.preview : this.final;\n const idle = !changed && !this.changing;\n if (aov !== 'motion') this._motion = undefined;\n else if (this._motion?.render !== current) {\n // Targets have independent histories. Prime every target switch, even\n // when a final small camera edit coincides with leaving preview.\n this._motion = {render: current, phase: this._motion ? 'priming' : 'moving'};\n } else if ((!idle && this._motion.phase !== 'priming') || (!current._completeFor('motion') && this._motion.phase === 'settled')) {\n this._motion.phase = 'moving';\n }\n const motion = this._motion;\n const imageState = loopImageState(this.final, this.display);\n if (idle && current === this.final && this.status === 'finished' && this.final.status === 'finished' && imageState === this._finishedImage && (!motion || motion.phase === 'settled')) return this.status;\n // Invalidate a completed filter before refinement when display settings changed.\n if (this.status === 'finished' && imageState !== this._finishedImage && this.final.samples > 0) this._present(this.final);\n // Motion describes successive images. One unchanged image retires the last\n // displacement; afterwards leave the finished target idle as usual.\n if (motion?.phase === 'moving' && idle && current._completeFor('motion')) {\n current._restartAovs(); motion.phase = 'settling';\n }\n const refill = !aov && idle && current === this.final;\n let status: RenderStatus;\n if (refill) {\n // Keep the loop's short synchronous budget; the public helper uses an\n // ordinary refine(). Selection/activity are application policy, revoked\n // through the same signal as input, stop and the next display frame.\n void current._refineUntil(performance.now() + 1000 / 60, controller.signal,\n {batchSamples: current.batchSamples, targetBatchTimeMs: 4}, () => {\n if ([...this._syncs].some(sync => sync.active) || this.select({changing: false}) !== 'final') controller.abort();\n }).then(() => {\n if (!controller.signal.aborted && current.status === 'error') this._setStatus('error');\n });\n status = current.status;\n } else status = refine(current);\n if (motion?.phase === 'priming' && status === 'finished') {\n current._restartAovs(); motion.phase = 'settling'; status = refine(current);\n }\n if (motion?.phase === 'settling' && status === 'finished') motion.phase = 'settled';\n // Keep the canvas on the last completed image while filtering the next\n // preview; presenting its raw sample here would overwrite the denoise above.\n const waitingForPreview = !!this.preview && ((current === this.preview && status === 'converging' && samples(current) === 0) || (!aov && this.coalesceSceneUpdates && this.preview.denoising)) &&\n (current === this.preview || (!current._completeFor(this.display.channel) && current.fallback === this.preview));\n if (waitingForPreview) this._previewFrameOwner = current;\n else this._present(current);\n // Execution may already be tracing final tiles while the canvas still shows\n // preview. Only a successful presentation transfers ownership of the image.\n const previewing = waitingForPreview || (!aov && current === this.preview && current.denoising) || (!!this.preview && this._presented === this.preview);\n const next = status === 'error' ? 'error' : previewing ? 'previewing' : status;\n this._finishedImage = next === 'finished' ? loopImageState(this.final, this.display) : undefined;\n if (refill && !previewing && !controller.signal.aborted && current._refilling) {\n // Manual tick grants work only until the next display frame.\n this._cancelRefillFrame = scheduleFrame(() => this._cancelRefill());\n } else controller.abort();\n return this._setStatus(next);\n }\n private _cancelRefill(): void {\n this._refillController?.abort(); this._refillController = undefined;\n this._cancelRefillFrame?.(); this._cancelRefillFrame = undefined;\n }\n private _schedule(): void {\n if (!this._running || this._busy || this._cancelScheduled !== undefined || (typeof document !== 'undefined' && document.hidden)) return;\n this._cancelScheduled = scheduleFrame(() => { this._cancelScheduled = undefined; try {this._tick();} finally {this._schedule();} });\n }\n // Input may finish before the next sync update (for example a quick drag).\n // Revoke the old frame's lease at dispatch, before a GPU fence can refill it.\n private readonly _inputEvents = ['pointerdown', 'pointermove', 'pointerup', 'wheel', 'keydown', 'input', 'change'] as const;\n private _input = (): void => { this._cancelRefill(); };\n private _visibility = (): void => {\n if (document.hidden) {this._cancelFrame(); this._cancelRefill();} else this._schedule();\n };\n private _cancelFrame(): void { this._cancelScheduled?.(); this._cancelScheduled = undefined; }\n /** Starts an idempotent loop; uses a 16 ms timer without rAF. Hidden pages pause automatically. */ start(): void { this._assertAlive(); this._running = true; this._schedule(); }\n /** Stops scheduling without discarding accumulated images. */ stop(): void { this._running = false; this._cancelFrame(); this._cancelRefill(); }\n /** Pauses ticks, converges final, presents it, and resumes a previously running loop. */\n async converge(options: ConvergeOptions): Promise<ConvergeResult> {\n this._assertAlive(); if (this._busy) throw new Error('RenderLoop convergence is already running.');\n this._busy = true; this._previewFrameOwner = undefined; this._cancelFrame(); this._cancelRefill();\n try {\n for (const sync of this._syncs) sync.update(); this.engine.update();\n this._setStatus('preparing');\n const result = await this.final.converge({...options, onProgress: progress => {\n this._setStatus(progress.stage === 'denoising' ? 'denoising' : this.final.status);\n options.onProgress?.(progress);\n }});\n this._present(this.final); this._setStatus('finished'); return result;\n } catch (error) {this._setStatus('error'); throw error;}\n finally {this._busy = false; this._schedule();}\n }\n /** Stops the loop and releases renders it created. Supplied renders/syncs remain owned by the caller. */\n dispose(): void {\n if (this._disposed) return;\n this.stop(); this._disposed = true; this._unsubscribe(); this._events.clear(); this._syncs.clear();\n if (typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this._visibility);\n for (const event of this._inputEvents) document.removeEventListener(event, this._input, true);\n }\n for (const render of this._owned) render.dispose(); this._owned.clear();\n }\n}\n"]}
package/lib/main.d.ts CHANGED
@@ -51,7 +51,7 @@ export type { EngineParams, EngineInfo, EngineDiagnostics, PrepareOptions, BVHBu
51
51
  export { default as Display } from './Display.js';
52
52
  export type { BlobOptions, DisplayChannel, AovIdComponent, DisplaySettings, PostProcess, PostProcessContext } from './Display.js';
53
53
  export { default as Render } from './Render.js';
54
- export type { RenderOptions, RenderSettings, RefineOptions, ConvergeOptions, ConvergeResult, DenoiserOptions, Denoiser, DenoiseInput, CustomDenoiserOptions, DenoiseSchedule, JNLMDenoiserOptions, OIDNDenoiserOptions, RenderStatus, SampleEvent } from './Render.js';
54
+ export type { RenderOptions, RenderSettings, CausticSettings, RefineOptions, ConvergeOptions, ConvergeResult, DenoiserOptions, Denoiser, DenoiseInput, CustomDenoiserOptions, DenoiseSchedule, JNLMDenoiserOptions, OIDNDenoiserOptions, RenderStatus, SampleEvent } from './Render.js';
55
55
  export { default as Sync } from './Sync.js';
56
56
  export { default as RenderLoop } from './RenderLoop.js';
57
57
  export type { RenderLoopOptions, RenderLoopStatus } from './RenderLoop.js';
package/lib/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAEvD;;;;;;;;;GASG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAYvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAY1D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EACL,OAAO,IAAI,QAAQ,EACnB,SAAS,IAAI,iBAAiB,EAC/B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAKxE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAIxD,SAAS;AACT,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EACL,OAAO,IAAI,UAAU,EACrB,aAAa,EACb,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAE/B,2BAA2B;AAC3B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAOjF,mBAAmB;AACnB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAO1D,oCAAoC;AACpC,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGxD,OAAO,EAAC,8BAA8B,EAAC,MAAM,kCAAkC,CAAC","sourcesContent":["/// <reference types=\"@webgpu/types\" preserve=\"true\" />\n\n/**\n * MuTracer: a physically based WebGPU path tracer with a\n * WebGL 2 fallback.\n *\n * Build a {@link Scene} from {@link Mesh}es and lights (or convert a Three.js\n * scene with {@link fromTHREEScene}), then call {@link Engine.update} and {@link Render.refine} once\n * per animation frame.\n *\n * @packageDocumentation\n */\nexport { VERSION } from './version.js';\n\nexport type {\n AlphaBlendStrategy,\n ShaderCompilationDiagnostics,\n ToneMapping\n} from './renderer/RenderingPipeline.js';\nexport type {\n OfflineAdaptiveSamplingOptions,\n OfflineVarianceHistory\n} from './renderer/OfflineAdaptiveSampling.js';\nexport type { OIDNModel, OIDNEngine, OIDNPrecision, OIDNHDRTransfer, OIDNDynamicTileOptions, OIDNDynamicTileSetting, OIDNAuxiliaryModelUrls } from './oidn.js';\nexport { DEFAULT_JNLM_OPTIONS } from './renderer/jnlm.js';\nexport type { JNLMOptions } from './renderer/jnlm.js';\n\n// Scene description\nexport type {\n AnalyticLight,\n EquirectBackground,\n GroundedSkyboxBackground,\n Scene,\n SceneBackground,\n SceneLight\n} from './scene/Scene.js';\nexport { default as Camera } from './scene/Camera.js';\nexport { default as Mesh } from './scene/Mesh.js';\nexport { default as InstancedMesh } from './scene/InstancedMesh.js';\nexport type { InstancedMeshOptions } from './scene/InstancedMesh.js';\nexport { default as SceneNode } from './scene/SceneNode.js';\nexport {\n default as Geometry,\n Attribute as GeometryAttribute\n} from './scene/Geometry.js';\nexport type { GeometryInit } from './scene/Geometry.js';\nexport type { OpenPBRMaterialParams } from './scene/OpenPBRMaterial.js';\nexport { default as OpenPBRMaterial } from './scene/OpenPBRMaterial.js';\nexport type {\n MaterialAlphaMode,\n UVProjection\n} from './scene/OpenPBRMaterial.js';\nexport { default as ProceduralSky } from './scene/ProceduralSky.js';\nexport type { ProceduralSkyOptions } from './scene/ProceduralSky.js';\nexport { default as Texture } from './scene/Texture.js';\nexport type { TextureDataSource, TextureWrapMode, TextureColorSpace } from './scene/Texture.js';\nexport type { ColorRGB, ColorRGBA, Vec2, Vec3, Mat4 } from './types.js';\n\n// Lights\nexport { default as AmbientLight } from './scene/AmbientLight.js';\nexport { default as DirectionalLight } from './scene/DirectionalLight.js';\nexport { default as RectLight } from './scene/RectLight.js';\nexport { default as SphereLight } from './scene/SphereLight.js';\nexport { default as SpotLight } from './scene/SpotLight.js';\nexport { default as EnvironmentLight } from './scene/EnvironmentLight.js';\nexport {\n default as IESProfile,\n IESParseError,\n parseIESProfile\n} from './scene/IESProfile.js';\n\n// Loaders and integrations\nexport { loadRGBE, parseRGBE } from './util/loadRGBE.js';\nexport { fromTHREECamera, fromTHREEScene, THREESync } from './util/fromTHREE.js';\nexport type {\n FromTHREESceneOptions,\n THREESyncOptions, THREEControls,\n FromTHREECameraOptions\n} from './util/fromTHREE.js';\n\n// Geometry helpers\nexport {\n createCubeGeometry,\n createCurvePlaneGeometry,\n createPlaneGeometry,\n createSphereGeometry\n} from './util/commonGeometry.js';\nexport {\n generateVertexNormals,\n generateVertexTangents\n} from './util/geometry.js';\nexport { computeMeshesBoundingBox } from './util/mesh.js';\n\n// BVH\nexport type { TinyBvhLayout } from './tinybvh/TinyBvhBuilder.js';\n\nexport type { SamplingPattern } from './renderer/sampling.js';\n\n// Independent rendering mechanisms.\nexport { default as Engine } from './Engine.js';\nexport type { EngineParams, EngineInfo, EngineDiagnostics, PrepareOptions, BVHBuilder, DepthSampleArea, TextureAtlasLimits } from './Engine.js';\nexport { default as Display } from './Display.js';\nexport type { BlobOptions, DisplayChannel, AovIdComponent, DisplaySettings, PostProcess, PostProcessContext } from './Display.js';\nexport { default as Render } from './Render.js';\nexport type { RenderOptions, RenderSettings, RefineOptions, ConvergeOptions, ConvergeResult, DenoiserOptions, Denoiser, DenoiseInput, CustomDenoiserOptions, DenoiseSchedule, JNLMDenoiserOptions, OIDNDenoiserOptions, RenderStatus, SampleEvent } from './Render.js';\n\nexport { default as Sync } from './Sync.js';\nexport { default as RenderLoop } from './RenderLoop.js';\nexport type { RenderLoopOptions, RenderLoopStatus } from './RenderLoop.js';\n\nexport {getRecommendedDeviceDescriptor} from './renderer/deviceRequirements.js';\n\nexport type {AovKind} from './renderer/aov.js';\n"]}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAEvD;;;;;;;;;GASG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAYvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAY1D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EACL,OAAO,IAAI,QAAQ,EACnB,SAAS,IAAI,iBAAiB,EAC/B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAKxE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAIxD,SAAS;AACT,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EACL,OAAO,IAAI,UAAU,EACrB,aAAa,EACb,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAE/B,2BAA2B;AAC3B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAOjF,mBAAmB;AACnB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAO1D,oCAAoC;AACpC,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGxD,OAAO,EAAC,8BAA8B,EAAC,MAAM,kCAAkC,CAAC","sourcesContent":["/// <reference types=\"@webgpu/types\" preserve=\"true\" />\n\n/**\n * MuTracer: a physically based WebGPU path tracer with a\n * WebGL 2 fallback.\n *\n * Build a {@link Scene} from {@link Mesh}es and lights (or convert a Three.js\n * scene with {@link fromTHREEScene}), then call {@link Engine.update} and {@link Render.refine} once\n * per animation frame.\n *\n * @packageDocumentation\n */\nexport { VERSION } from './version.js';\n\nexport type {\n AlphaBlendStrategy,\n ShaderCompilationDiagnostics,\n ToneMapping\n} from './renderer/RenderingPipeline.js';\nexport type {\n OfflineAdaptiveSamplingOptions,\n OfflineVarianceHistory\n} from './renderer/OfflineAdaptiveSampling.js';\nexport type { OIDNModel, OIDNEngine, OIDNPrecision, OIDNHDRTransfer, OIDNDynamicTileOptions, OIDNDynamicTileSetting, OIDNAuxiliaryModelUrls } from './oidn.js';\nexport { DEFAULT_JNLM_OPTIONS } from './renderer/jnlm.js';\nexport type { JNLMOptions } from './renderer/jnlm.js';\n\n// Scene description\nexport type {\n AnalyticLight,\n EquirectBackground,\n GroundedSkyboxBackground,\n Scene,\n SceneBackground,\n SceneLight\n} from './scene/Scene.js';\nexport { default as Camera } from './scene/Camera.js';\nexport { default as Mesh } from './scene/Mesh.js';\nexport { default as InstancedMesh } from './scene/InstancedMesh.js';\nexport type { InstancedMeshOptions } from './scene/InstancedMesh.js';\nexport { default as SceneNode } from './scene/SceneNode.js';\nexport {\n default as Geometry,\n Attribute as GeometryAttribute\n} from './scene/Geometry.js';\nexport type { GeometryInit } from './scene/Geometry.js';\nexport type { OpenPBRMaterialParams } from './scene/OpenPBRMaterial.js';\nexport { default as OpenPBRMaterial } from './scene/OpenPBRMaterial.js';\nexport type {\n MaterialAlphaMode,\n UVProjection\n} from './scene/OpenPBRMaterial.js';\nexport { default as ProceduralSky } from './scene/ProceduralSky.js';\nexport type { ProceduralSkyOptions } from './scene/ProceduralSky.js';\nexport { default as Texture } from './scene/Texture.js';\nexport type { TextureDataSource, TextureWrapMode, TextureColorSpace } from './scene/Texture.js';\nexport type { ColorRGB, ColorRGBA, Vec2, Vec3, Mat4 } from './types.js';\n\n// Lights\nexport { default as AmbientLight } from './scene/AmbientLight.js';\nexport { default as DirectionalLight } from './scene/DirectionalLight.js';\nexport { default as RectLight } from './scene/RectLight.js';\nexport { default as SphereLight } from './scene/SphereLight.js';\nexport { default as SpotLight } from './scene/SpotLight.js';\nexport { default as EnvironmentLight } from './scene/EnvironmentLight.js';\nexport {\n default as IESProfile,\n IESParseError,\n parseIESProfile\n} from './scene/IESProfile.js';\n\n// Loaders and integrations\nexport { loadRGBE, parseRGBE } from './util/loadRGBE.js';\nexport { fromTHREECamera, fromTHREEScene, THREESync } from './util/fromTHREE.js';\nexport type {\n FromTHREESceneOptions,\n THREESyncOptions, THREEControls,\n FromTHREECameraOptions\n} from './util/fromTHREE.js';\n\n// Geometry helpers\nexport {\n createCubeGeometry,\n createCurvePlaneGeometry,\n createPlaneGeometry,\n createSphereGeometry\n} from './util/commonGeometry.js';\nexport {\n generateVertexNormals,\n generateVertexTangents\n} from './util/geometry.js';\nexport { computeMeshesBoundingBox } from './util/mesh.js';\n\n// BVH\nexport type { TinyBvhLayout } from './tinybvh/TinyBvhBuilder.js';\n\nexport type { SamplingPattern } from './renderer/sampling.js';\n\n// Independent rendering mechanisms.\nexport { default as Engine } from './Engine.js';\nexport type { EngineParams, EngineInfo, EngineDiagnostics, PrepareOptions, BVHBuilder, DepthSampleArea, TextureAtlasLimits } from './Engine.js';\nexport { default as Display } from './Display.js';\nexport type { BlobOptions, DisplayChannel, AovIdComponent, DisplaySettings, PostProcess, PostProcessContext } from './Display.js';\nexport { default as Render } from './Render.js';\nexport type { RenderOptions, RenderSettings, CausticSettings, RefineOptions, ConvergeOptions, ConvergeResult, DenoiserOptions, Denoiser, DenoiseInput, CustomDenoiserOptions, DenoiseSchedule, JNLMDenoiserOptions, OIDNDenoiserOptions, RenderStatus, SampleEvent } from './Render.js';\n\nexport { default as Sync } from './Sync.js';\nexport { default as RenderLoop } from './RenderLoop.js';\nexport type { RenderLoopOptions, RenderLoopStatus } from './RenderLoop.js';\n\nexport {getRecommendedDeviceDescriptor} from './renderer/deviceRequirements.js';\n\nexport type {AovKind} from './renderer/aov.js';\n"]}
package/lib/oidn.d.ts CHANGED
@@ -40,6 +40,6 @@ export declare const DEFAULT_OIDN_WEIGHTS_PACKAGE_BASE_URL = "https://cdn.jsdeli
40
40
  * Fallback for bundled standard/small weights when application assets fail.
41
41
  * Defaults to jsDelivr's `@meimu/mutracer@VERSION/oidn/weights/` directory.
42
42
  */
43
- export declare const DEFAULT_OIDN_WEIGHTS_BASE_URL = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.2.0/oidn/weights/";
43
+ export declare const DEFAULT_OIDN_WEIGHTS_BASE_URL = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.3.0/oidn/weights/";
44
44
  export declare function resolveOIDNModelUrl(model: OIDNModel, weightsBaseUrl?: string | URL): string;
45
45
  export declare function resolveOIDNAuxiliaryModelUrls(weightsBaseUrl?: string | URL): OIDNAuxiliaryModelUrls;
@@ -1,2 +1,2 @@
1
- export declare const standardWeightsUrl = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.2.0/oidn/weights/rt_hdr_alb_nrm.tza";
2
- export declare const smallWeightsUrl = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.2.0/oidn/weights/rt_hdr_alb_nrm_small.tza";
1
+ export declare const standardWeightsUrl = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.3.0/oidn/weights/rt_hdr_alb_nrm.tza";
2
+ export declare const smallWeightsUrl = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.3.0/oidn/weights/rt_hdr_alb_nrm_small.tza";
@@ -4,7 +4,8 @@ export declare class GPUTraceQueue {
4
4
  private pendingMs;
5
5
  private pending;
6
6
  constructor(queue: GPUQueue);
7
+ get hasPending(): boolean;
7
8
  available(budgetMs: number): number;
8
- whenAvailable(): Promise<void>;
9
+ whenAvailable(): Promise<boolean>;
9
10
  track(estimatedMs: number): void;
10
11
  }
@@ -6,11 +6,13 @@ export class GPUTraceQueue {
6
6
  constructor(queue) {
7
7
  this.queue = queue;
8
8
  }
9
+ get hasPending() { return this.pending.size > 0; }
9
10
  available(budgetMs) {
10
11
  return Math.max(0, budgetMs - this.pendingMs);
11
12
  }
12
13
  whenAvailable() {
13
- return this.pending.values().next().value ?? Promise.resolve();
14
+ const pending = this.pending.values().next().value;
15
+ return pending ? pending.then(() => true) : Promise.resolve(false);
14
16
  }
15
17
  track(estimatedMs) {
16
18
  this.pendingMs += estimatedMs;
@@ -1 +1 @@
1
- {"version":3,"file":"GPUTraceQueue.js","sourceRoot":"","sources":["../../src/renderer/GPUTraceQueue.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,OAAO,aAAa;IAIJ;IAHZ,SAAS,GAAG,CAAC,CAAC;IACd,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;IAE3C,YAAoB,KAAe;QAAf,UAAK,GAAL,KAAK,CAAU;IAAG,CAAC;IAEvC,SAAS,CAAC,QAAgB;QACxB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,WAAmB;QACvB,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC;QAC9B,4EAA4E;QAC5E,6EAA6E;QAC7E,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;YAC3D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAChC,qEAAqE;YACrE,wEAAwE;YACxE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;gBAAE,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QAC7C,CAAC,CAAC;QACF,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;CACF","sourcesContent":["/** Shared by resident targets so switching images cannot reset queued work. */\nexport class GPUTraceQueue {\n private pendingMs = 0;\n private pending = new Set<Promise<void>>();\n\n constructor(private queue: GPUQueue) {}\n\n available(budgetMs: number): number {\n return Math.max(0, budgetMs - this.pendingMs);\n }\n\n whenAvailable(): Promise<void> {\n return this.pending.values().next().value ?? Promise.resolve();\n }\n\n track(estimatedMs: number): void {\n this.pendingMs += estimatedMs;\n // Fence each sample, rather than the entire batch: a later display tick can\n // replace completed samples while the tail of the previous batch still runs.\n const retire = () => {\n this.pendingMs = Math.max(0, this.pendingMs - estimatedMs);\n this.pending.delete(completion);\n // Subtracting estimates leaves rounding residue. An empty queue must\n // admit a sample as long as the budget, or nothing would wake it again.\n if (!this.pending.size) this.pendingMs = 0;\n };\n const completion = this.queue.onSubmittedWorkDone().then(retire, retire);\n this.pending.add(completion);\n }\n}\n"]}
1
+ {"version":3,"file":"GPUTraceQueue.js","sourceRoot":"","sources":["../../src/renderer/GPUTraceQueue.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,OAAO,aAAa;IAIJ;IAHZ,SAAS,GAAG,CAAC,CAAC;IACd,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;IAE3C,YAAoB,KAAe;QAAf,UAAK,GAAL,KAAK,CAAU;IAAG,CAAC;IAEvC,IAAI,UAAU,KAAc,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;IAE3D,SAAS,CAAC,QAAgB;QACxB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;IAED,aAAa;QACX,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QACnD,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,WAAmB;QACvB,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC;QAC9B,4EAA4E;QAC5E,6EAA6E;QAC7E,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;YAC3D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAChC,qEAAqE;YACrE,wEAAwE;YACxE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;gBAAE,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QAC7C,CAAC,CAAC;QACF,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;CACF","sourcesContent":["/** Shared by resident targets so switching images cannot reset queued work. */\nexport class GPUTraceQueue {\n private pendingMs = 0;\n private pending = new Set<Promise<void>>();\n\n constructor(private queue: GPUQueue) {}\n\n get hasPending(): boolean { return this.pending.size > 0; }\n\n available(budgetMs: number): number {\n return Math.max(0, budgetMs - this.pendingMs);\n }\n\n whenAvailable(): Promise<boolean> {\n const pending = this.pending.values().next().value;\n return pending ? pending.then(() => true) : Promise.resolve(false);\n }\n\n track(estimatedMs: number): void {\n this.pendingMs += estimatedMs;\n // Fence each sample, rather than the entire batch: a later display tick can\n // replace completed samples while the tail of the previous batch still runs.\n const retire = () => {\n this.pendingMs = Math.max(0, this.pendingMs - estimatedMs);\n this.pending.delete(completion);\n // Subtracting estimates leaves rounding residue. An empty queue must\n // admit a sample as long as the budget, or nothing would wake it again.\n if (!this.pending.size) this.pendingMs = 0;\n };\n const completion = this.queue.onSubmittedWorkDone().then(retire, retire);\n this.pending.add(completion);\n }\n}\n"]}
@@ -157,6 +157,10 @@ export interface RenderingDiagnostics {
157
157
  };
158
158
  };
159
159
  gpuTraceTiming?: {
160
+ /** Last light-tracing batch time in milliseconds. Default undefined until measured. */ causticTimeMs?: number;
161
+ /** Last photon-map batch time in milliseconds. Default undefined until measured. */ photonMappingTimeMs?: number;
162
+ /** Photon emission, count, block scan, sum scan and scatter times in milliseconds. Default undefined until measured. */ photonStagesMs?: number[];
163
+ /** Camera path kernel time in milliseconds. Default undefined until measured. */ pathTracingTimeMs?: number;
160
164
  tileTimeMs: number;
161
165
  tileTimePerSampleMs?: number;
162
166
  estimatedFullFrameTimeMs: number;
@@ -1 +1 @@
1
- {"version":3,"file":"RenderingPipeline.js","sourceRoot":"","sources":["../../src/renderer/RenderingPipeline.ts"],"names":[],"mappings":"AAqLA,OAAO,EAAC,qBAAqB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,+BAA+B,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,8BAA8B,EAAE,qBAAqB,EAAC,MAAM,sBAAsB,CAAC","sourcesContent":["import type {PostProcess} from '../Display.js';\nimport type Render from '../Render.js';\nimport type {DenoiserHandle, OIDNWeb} from './denoiser.js';\nimport type {DenoiseSchedule} from '../Render.js';\nimport type { DepthSampleArea } from './depthQuery.js';\nimport Camera from '../scene/Camera.js';\nimport Mesh from '../scene/Mesh.js';\nimport Geometry from '../scene/Geometry.js';\nimport OpenPBRMaterial from '../scene/OpenPBRMaterial.js';\nimport type { SceneBackground, SceneLight } from '../scene/Scene.js';\nimport type { ColorRGB } from '../types.js';\nimport type { TextureAtlasStats } from './MaterialTable.js';\nimport type {\n OfflineAdaptiveSamplingOptions,\n OfflineAdaptiveSamplingResult\n} from './OfflineAdaptiveSampling.js';\n\nexport type ToneMapping =\n | 'agx'\n | 'aces'\n | 'cineon'\n | 'reinhard'\n | 'linear';\n\nexport interface ToneMappingParams {\n /** Linear exposure multiplier. Default `1`. */\n exposure?: number;\n /** Display tone mapper. Default `agx`. */\n toneMapping?: ToneMapping;\n /** Contrast multiplier. Default `1`. */\n contrast?: number;\n /** Saturation multiplier. Default `1`. */\n saturation?: number;\n /** Color temperature adjustment in [-1, 1]. Default `0`. */\n temperature?: number;\n /** Green/magenta adjustment in [-1, 1]. Default `0`. */\n tint?: number;\n /** Vignette strength in [0, 1]. Default `0`. */\n vignette?: number;\n}\n\nexport type DisplayChannel =\n | 'final'\n | 'shadow'\n | 'albedo'\n | 'normal'\n | 'shadowCatcher'\n | import('./aov.js').AovKind;\n\n/** Primary-ray policy for glTF BLEND materials. */\nexport type AlphaBlendStrategy =\n | 'stochastic'\n | 'deterministic-source-over';\n\n/** Generated source measurements for one shader module. */\nexport interface ShaderModuleCompilationDiagnostics {\n /** Module or pipeline diagnostic label. */\n label: string;\n /** Generated shader source size in bytes. */\n sourceBytes: number;\n /** Generated shader source line count. */\n sourceLines: number;\n /** Stable source-level fingerprint for diagnosing cache-key churn. */\n sourceFingerprint: string;\n}\n\n/** Compilation measurements for one shader pipeline/program. */\nexport interface ShaderPipelineCompilationDiagnostics {\n /** Module or pipeline diagnostic label. */\n label: string;\n /** Compute entry-point name. */\n entryPoint: string;\n /**\n * Whether this pipeline belongs to the minimum set needed to present a\n * usable first image. Optional reuse and quality stages are false even\n * while the current eager compiler still waits for them.\n */\n firstFrameRequired: boolean;\n /** Current compilation state. */\n status: 'queued' | 'compiling' | 'ready' | 'failed';\n /** Milliseconds from the start of this pipeline compilation batch. */\n startedAtMs?: number;\n /** Milliseconds from the start of this pipeline compilation batch. */\n endedAtMs?: number;\n /** Pipeline compilation duration in milliseconds; undefined until completed. */\n durationMs?: number;\n /** Number of pipelines compiling when this one started; undefined before start. */\n concurrentCompilationCount?: number;\n /** Failure message; undefined without a compilation error. */\n error?: string;\n}\n\n/** Source generation and asynchronous pipeline compilation measurements. */\nexport interface ShaderCompilationDiagnostics {\n /** Current compilation state. */\n status: 'compiling' | 'ready' | 'failed';\n /** Generated shader source size in bytes. */\n sourceBytes: number;\n /** Generated shader source line count. */\n sourceLines: number;\n /** Total pipelines in the batch. */\n pipelineCount: number;\n /** Number of pipelines successfully completed. */\n completedPipelineCount: number;\n /** CPU shader source generation time in milliseconds. */\n sourceGenerationTimeMs: number;\n /** Shader module creation time in milliseconds. */\n moduleCreationTimeMs: number;\n /** Per-module source measurements. */\n modules: ShaderModuleCompilationDiagnostics[];\n /** Per-pipeline timing and status measurements. */\n pipelines: ShaderPipelineCompilationDiagnostics[];\n /** Configured pool size, capped to the number of pipelines in this batch. */\n maximumConcurrentPipelineCount: number;\n /** Largest number of createComputePipelineAsync calls active at once. */\n peakConcurrentPipelineCount: number;\n /** Batch pipeline compilation time in milliseconds; undefined until completed. */\n pipelineCompilationTimeMs?: number;\n /** Total batch preparation time in milliseconds; undefined until completed. */\n totalTimeMs?: number;\n /** Failure message; undefined without a compilation error. */\n error?: string;\n}\n\nexport interface RenderingDiagnostics {\n /** Label of the last complete target presented; undefined before the first image. */\n presentedTarget?: string;\n /** Whether the displayed target contains a complete image. Default false. */\n presentedComplete?: boolean;\n /** Resident target dimensions and allocated GPU bytes, including denoise resources. */\n targets?: { label: string; width: number; height: number; bytes: number }[];\n hdrPresentation?: {\n requested: boolean;\n active: boolean;\n /** Largest encoded RGB component sent to the HDR presentation pass. */\n peakDisplayValue?: number;\n };\n textureAtlas?: TextureAtlasStats;\n /** Material texture storage selection and estimated payload; driver allocation overhead is excluded. */\n materialTextures?: {\n requested: 'atlas' | 'auto';\n active: 'atlas' | 'bindless';\n /** Reason auto selected atlas; undefined when no fallback occurred. */\n fallbackReason?: string;\n textureCount: number;\n estimatedBytes: number;\n scale: number;\n /** Metadata buffer bytes; zero for atlas. */\n metadataBytes: number;\n /** Resource-table slots; zero for atlas. */\n resourceTableCapacity: number;\n /** Payload and metadata waiting for previous GPU submissions; zero when none. */\n retiredBytes: number;\n };\n /** Shader compilation measurements: current WebGPU batch or cumulative WebGL programs. */\n shaderCompilation?: ShaderCompilationDiagnostics;\n /** Light-selection table summary (WebGPU). */\n lightSampling?: {\n emissiveTriangles: number;\n activeChoices: number;\n totalWeight: number;\n domains: Record<\n 'environment' | 'infinite' | 'localAndEmissive',\n { count: number; weight: number; pmf: number }\n >;\n };\n /** Traversal stack capacities compiled into the current WebGPU shader. */\n bvh?: {\n tlasTraversalStackSize?: number;\n blasTraversalStackSize?: number;\n /** Last static preparation statistics, excluding queue and WASM loading time. */\n lastBuild?: { geometryCount: number; bvhTimeMs: number };\n };\n gpuTraceTiming?: {\n tileTimeMs: number;\n tileTimePerSampleMs?: number;\n estimatedFullFrameTimeMs: number;\n tileCount: number;\n };\n}\n\nexport {DEFAULT_BEVEL_SAMPLES, MIN_BEVEL_SAMPLES, MAX_BEVEL_SAMPLES, DEFAULT_DIRECT_LIGHT_CANDIDATES, MIN_DIRECT_LIGHT_CANDIDATES, MAX_DIRECT_LIGHT_CANDIDATES, normalizeDirectLightCandidates, normalizeBevelSamples} from './renderingLimits.js';\n\n/** Shared scene resources; uploaded once per committed revision. */\nexport interface SceneResources {\n /** Returns true when scene geometry, materials, or instance transforms changed. */\n setMeshes(meshes: Mesh[], update?: {\n transforms?: readonly Mesh[];\n colors?: readonly Mesh[];\n geometries?: readonly Geometry[];\n materials?: readonly OpenPBRMaterial[];\n }): boolean;\n /** Changes the software memory guard used when packing material textures. */\n setTextureAtlasBudget(maxBytes: number): boolean;\n setLights(lights: SceneLight[]): void;\n setBackground(background?: SceneBackground): void;\n getDiagnostics(): RenderingDiagnostics;\n dispose(): void;\n readDepthSamples(area: DepthSampleArea): Promise<Float32Array | undefined>;\n}\n/** Explicit execution and composition for one accumulation. */\nexport interface RenderPasses {\n isFirstFrame(): boolean;\n /** Discard accumulated samples and any asynchronous denoise output. */\n restartSamples(): void;\n trace(camera: Camera, maxSamples: number): boolean;\n drawPostProcess(): void;\n /** Apply display-only passes to the last composed image; absent on WebGL. */\n applyPostProcesses?(passes: readonly PostProcess[], render: Render): void;\n getOutputTexture?(kind: 'hdr' | 'display'): GPUTexture | undefined;\n /** Configure deterministic headless batches used by offline frame export. */\n setOfflineRenderOptions(options: {\n samplesPerBatch: number;\n deferPostProcess: boolean;\n sampleSequenceOffset: number;\n }): void;\n /** Store luminance second moments in the normal output during a pilot pass. */\n setVarianceMoments(enabled: boolean): void;\n /** Skip pixels once their independent final-pass target has been reached. */\n setAdaptiveSamplingTargets(targets?: {\n width: number;\n height: number;\n data: Float32Array;\n }): void;\n /** Generate final sample targets on GPU; WebGL returns undefined. */\n prepareOfflineAdaptiveSampling(\n options: OfflineAdaptiveSamplingOptions\n ): Promise<OfflineAdaptiveSamplingResult | undefined>;\n /** Enables extended-range float canvas presentation when the host supports it. */\n setHDROutputEnabled?(enabled: boolean): boolean;\n setToneMappingParams(params: ToneMappingParams): boolean;\n setSize(width: number, height: number): void;\n /**\n * Denoises the current image with an explicitly selected built-in or custom filter. Resolves whether the result is now displayed.\n */\n performDenoise?(\n denoiser: DenoiserHandle,\n alphaDenoiser?: OIDNWeb,\n schedule?: DenoiseSchedule,\n signal?: AbortSignal\n ): Promise<boolean>;\n /** Drops a denoise in flight; the next draw invalidates its output. */\n cancelDenoise?(): void;\n /** Keep the last completed OIDN image visible while static while-converging batches accumulate. */\n setPreserveDenoisedOutput?(preserve: boolean): void;\n getTotalSamplesRendered(): number;\n getDiagnostics(): RenderingDiagnostics;\n /** Waits for asynchronous timestamp diagnostics without changing samples. */\n flushDiagnostics(): Promise<void>;\n setShadowCatcherParams(color: ColorRGB, alpha: number): boolean;\n setBloomParams(opts: {\n intensity: number;\n threshold: number;\n radius: number;\n }): boolean;\n setOnSampleRendered(\n cb: (sampleCount: number, isFirstFrame: boolean, frameTime: number) => void\n ): void;\n setOutput(output: DisplayChannel): boolean;\n setAovDisplayOptions?(options: import('./aovDisplay.js').AovDisplayOptions): void;\n dispose(): void;\n aovReady?(kind: import('./aov.js').AovKind): boolean;\n /** Updates optional surface outputs without tracing beauty; false while compiling. */\n refineAovs?(camera: Camera, samples?: number): boolean;\n restartAovs?(): void;\n getAovSamples?(): number;\n readAov?(kind: import('./aov.js').AovKind): Promise<{width: number; height: number; data: Float32Array | Uint32Array}>;\n readOutput(kind: 'hdr' | 'denoised' | 'albedo' | 'normal'): Promise<{\n data: Float32Array;\n width: number;\n height: number;\n }>;\n}\n"]}
1
+ {"version":3,"file":"RenderingPipeline.js","sourceRoot":"","sources":["../../src/renderer/RenderingPipeline.ts"],"names":[],"mappings":"AAyLA,OAAO,EAAC,qBAAqB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,+BAA+B,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,8BAA8B,EAAE,qBAAqB,EAAC,MAAM,sBAAsB,CAAC","sourcesContent":["import type {PostProcess} from '../Display.js';\nimport type Render from '../Render.js';\nimport type {DenoiserHandle, OIDNWeb} from './denoiser.js';\nimport type {DenoiseSchedule} from '../Render.js';\nimport type { DepthSampleArea } from './depthQuery.js';\nimport Camera from '../scene/Camera.js';\nimport Mesh from '../scene/Mesh.js';\nimport Geometry from '../scene/Geometry.js';\nimport OpenPBRMaterial from '../scene/OpenPBRMaterial.js';\nimport type { SceneBackground, SceneLight } from '../scene/Scene.js';\nimport type { ColorRGB } from '../types.js';\nimport type { TextureAtlasStats } from './MaterialTable.js';\nimport type {\n OfflineAdaptiveSamplingOptions,\n OfflineAdaptiveSamplingResult\n} from './OfflineAdaptiveSampling.js';\n\nexport type ToneMapping =\n | 'agx'\n | 'aces'\n | 'cineon'\n | 'reinhard'\n | 'linear';\n\nexport interface ToneMappingParams {\n /** Linear exposure multiplier. Default `1`. */\n exposure?: number;\n /** Display tone mapper. Default `agx`. */\n toneMapping?: ToneMapping;\n /** Contrast multiplier. Default `1`. */\n contrast?: number;\n /** Saturation multiplier. Default `1`. */\n saturation?: number;\n /** Color temperature adjustment in [-1, 1]. Default `0`. */\n temperature?: number;\n /** Green/magenta adjustment in [-1, 1]. Default `0`. */\n tint?: number;\n /** Vignette strength in [0, 1]. Default `0`. */\n vignette?: number;\n}\n\nexport type DisplayChannel =\n | 'final'\n | 'shadow'\n | 'albedo'\n | 'normal'\n | 'shadowCatcher'\n | import('./aov.js').AovKind;\n\n/** Primary-ray policy for glTF BLEND materials. */\nexport type AlphaBlendStrategy =\n | 'stochastic'\n | 'deterministic-source-over';\n\n/** Generated source measurements for one shader module. */\nexport interface ShaderModuleCompilationDiagnostics {\n /** Module or pipeline diagnostic label. */\n label: string;\n /** Generated shader source size in bytes. */\n sourceBytes: number;\n /** Generated shader source line count. */\n sourceLines: number;\n /** Stable source-level fingerprint for diagnosing cache-key churn. */\n sourceFingerprint: string;\n}\n\n/** Compilation measurements for one shader pipeline/program. */\nexport interface ShaderPipelineCompilationDiagnostics {\n /** Module or pipeline diagnostic label. */\n label: string;\n /** Compute entry-point name. */\n entryPoint: string;\n /**\n * Whether this pipeline belongs to the minimum set needed to present a\n * usable first image. Optional reuse and quality stages are false even\n * while the current eager compiler still waits for them.\n */\n firstFrameRequired: boolean;\n /** Current compilation state. */\n status: 'queued' | 'compiling' | 'ready' | 'failed';\n /** Milliseconds from the start of this pipeline compilation batch. */\n startedAtMs?: number;\n /** Milliseconds from the start of this pipeline compilation batch. */\n endedAtMs?: number;\n /** Pipeline compilation duration in milliseconds; undefined until completed. */\n durationMs?: number;\n /** Number of pipelines compiling when this one started; undefined before start. */\n concurrentCompilationCount?: number;\n /** Failure message; undefined without a compilation error. */\n error?: string;\n}\n\n/** Source generation and asynchronous pipeline compilation measurements. */\nexport interface ShaderCompilationDiagnostics {\n /** Current compilation state. */\n status: 'compiling' | 'ready' | 'failed';\n /** Generated shader source size in bytes. */\n sourceBytes: number;\n /** Generated shader source line count. */\n sourceLines: number;\n /** Total pipelines in the batch. */\n pipelineCount: number;\n /** Number of pipelines successfully completed. */\n completedPipelineCount: number;\n /** CPU shader source generation time in milliseconds. */\n sourceGenerationTimeMs: number;\n /** Shader module creation time in milliseconds. */\n moduleCreationTimeMs: number;\n /** Per-module source measurements. */\n modules: ShaderModuleCompilationDiagnostics[];\n /** Per-pipeline timing and status measurements. */\n pipelines: ShaderPipelineCompilationDiagnostics[];\n /** Configured pool size, capped to the number of pipelines in this batch. */\n maximumConcurrentPipelineCount: number;\n /** Largest number of createComputePipelineAsync calls active at once. */\n peakConcurrentPipelineCount: number;\n /** Batch pipeline compilation time in milliseconds; undefined until completed. */\n pipelineCompilationTimeMs?: number;\n /** Total batch preparation time in milliseconds; undefined until completed. */\n totalTimeMs?: number;\n /** Failure message; undefined without a compilation error. */\n error?: string;\n}\n\nexport interface RenderingDiagnostics {\n /** Label of the last complete target presented; undefined before the first image. */\n presentedTarget?: string;\n /** Whether the displayed target contains a complete image. Default false. */\n presentedComplete?: boolean;\n /** Resident target dimensions and allocated GPU bytes, including denoise resources. */\n targets?: { label: string; width: number; height: number; bytes: number }[];\n hdrPresentation?: {\n requested: boolean;\n active: boolean;\n /** Largest encoded RGB component sent to the HDR presentation pass. */\n peakDisplayValue?: number;\n };\n textureAtlas?: TextureAtlasStats;\n /** Material texture storage selection and estimated payload; driver allocation overhead is excluded. */\n materialTextures?: {\n requested: 'atlas' | 'auto';\n active: 'atlas' | 'bindless';\n /** Reason auto selected atlas; undefined when no fallback occurred. */\n fallbackReason?: string;\n textureCount: number;\n estimatedBytes: number;\n scale: number;\n /** Metadata buffer bytes; zero for atlas. */\n metadataBytes: number;\n /** Resource-table slots; zero for atlas. */\n resourceTableCapacity: number;\n /** Payload and metadata waiting for previous GPU submissions; zero when none. */\n retiredBytes: number;\n };\n /** Shader compilation measurements: current WebGPU batch or cumulative WebGL programs. */\n shaderCompilation?: ShaderCompilationDiagnostics;\n /** Light-selection table summary (WebGPU). */\n lightSampling?: {\n emissiveTriangles: number;\n activeChoices: number;\n totalWeight: number;\n domains: Record<\n 'environment' | 'infinite' | 'localAndEmissive',\n { count: number; weight: number; pmf: number }\n >;\n };\n /** Traversal stack capacities compiled into the current WebGPU shader. */\n bvh?: {\n tlasTraversalStackSize?: number;\n blasTraversalStackSize?: number;\n /** Last static preparation statistics, excluding queue and WASM loading time. */\n lastBuild?: { geometryCount: number; bvhTimeMs: number };\n };\n gpuTraceTiming?: {\n /** Last light-tracing batch time in milliseconds. Default undefined until measured. */ causticTimeMs?:number;\n /** Last photon-map batch time in milliseconds. Default undefined until measured. */ photonMappingTimeMs?:number;\n /** Photon emission, count, block scan, sum scan and scatter times in milliseconds. Default undefined until measured. */ photonStagesMs?:number[];\n /** Camera path kernel time in milliseconds. Default undefined until measured. */ pathTracingTimeMs?:number;\n tileTimeMs: number;\n tileTimePerSampleMs?: number;\n estimatedFullFrameTimeMs: number;\n tileCount: number;\n };\n}\n\nexport {DEFAULT_BEVEL_SAMPLES, MIN_BEVEL_SAMPLES, MAX_BEVEL_SAMPLES, DEFAULT_DIRECT_LIGHT_CANDIDATES, MIN_DIRECT_LIGHT_CANDIDATES, MAX_DIRECT_LIGHT_CANDIDATES, normalizeDirectLightCandidates, normalizeBevelSamples} from './renderingLimits.js';\n\n/** Shared scene resources; uploaded once per committed revision. */\nexport interface SceneResources {\n /** Returns true when scene geometry, materials, or instance transforms changed. */\n setMeshes(meshes: Mesh[], update?: {\n transforms?: readonly Mesh[];\n colors?: readonly Mesh[];\n geometries?: readonly Geometry[];\n materials?: readonly OpenPBRMaterial[];\n }): boolean;\n /** Changes the software memory guard used when packing material textures. */\n setTextureAtlasBudget(maxBytes: number): boolean;\n setLights(lights: SceneLight[]): void;\n setBackground(background?: SceneBackground): void;\n getDiagnostics(): RenderingDiagnostics;\n dispose(): void;\n readDepthSamples(area: DepthSampleArea): Promise<Float32Array | undefined>;\n}\n/** Explicit execution and composition for one accumulation. */\nexport interface RenderPasses {\n isFirstFrame(): boolean;\n /** Discard accumulated samples and any asynchronous denoise output. */\n restartSamples(): void;\n trace(camera: Camera, maxSamples: number): boolean;\n drawPostProcess(): void;\n /** Apply display-only passes to the last composed image; absent on WebGL. */\n applyPostProcesses?(passes: readonly PostProcess[], render: Render): void;\n getOutputTexture?(kind: 'hdr' | 'display'): GPUTexture | undefined;\n /** Configure deterministic headless batches used by offline frame export. */\n setOfflineRenderOptions(options: {\n samplesPerBatch: number;\n deferPostProcess: boolean;\n sampleSequenceOffset: number;\n }): void;\n /** Store luminance second moments in the normal output during a pilot pass. */\n setVarianceMoments(enabled: boolean): void;\n /** Skip pixels once their independent final-pass target has been reached. */\n setAdaptiveSamplingTargets(targets?: {\n width: number;\n height: number;\n data: Float32Array;\n }): void;\n /** Generate final sample targets on GPU; WebGL returns undefined. */\n prepareOfflineAdaptiveSampling(\n options: OfflineAdaptiveSamplingOptions\n ): Promise<OfflineAdaptiveSamplingResult | undefined>;\n /** Enables extended-range float canvas presentation when the host supports it. */\n setHDROutputEnabled?(enabled: boolean): boolean;\n setToneMappingParams(params: ToneMappingParams): boolean;\n setSize(width: number, height: number): void;\n /**\n * Denoises the current image with an explicitly selected built-in or custom filter. Resolves whether the result is now displayed.\n */\n performDenoise?(\n denoiser: DenoiserHandle,\n alphaDenoiser?: OIDNWeb,\n schedule?: DenoiseSchedule,\n signal?: AbortSignal\n ): Promise<boolean>;\n /** Drops a denoise in flight; the next draw invalidates its output. */\n cancelDenoise?(): void;\n /** Keep the last completed OIDN image visible while static while-converging batches accumulate. */\n setPreserveDenoisedOutput?(preserve: boolean): void;\n getTotalSamplesRendered(): number;\n getDiagnostics(): RenderingDiagnostics;\n /** Waits for asynchronous timestamp diagnostics without changing samples. */\n flushDiagnostics(): Promise<void>;\n setShadowCatcherParams(color: ColorRGB, alpha: number): boolean;\n setBloomParams(opts: {\n intensity: number;\n threshold: number;\n radius: number;\n }): boolean;\n setOnSampleRendered(\n cb: (sampleCount: number, isFirstFrame: boolean, frameTime: number) => void\n ): void;\n setOutput(output: DisplayChannel): boolean;\n setAovDisplayOptions?(options: import('./aovDisplay.js').AovDisplayOptions): void;\n dispose(): void;\n aovReady?(kind: import('./aov.js').AovKind): boolean;\n /** Updates optional surface outputs without tracing beauty; false while compiling. */\n refineAovs?(camera: Camera, samples?: number): boolean;\n restartAovs?(): void;\n getAovSamples?(): number;\n readAov?(kind: import('./aov.js').AovKind): Promise<{width: number; height: number; data: Float32Array | Uint32Array}>;\n readOutput(kind: 'hdr' | 'denoised' | 'albedo' | 'normal'): Promise<{\n data: Float32Array;\n width: number;\n height: number;\n }>;\n}\n"]}
@@ -0,0 +1,48 @@
1
+ export { packCausticLightUniform } from './causticUniform.js';
2
+ import { type ResourceTable } from './wgpuBindless.js';
3
+ import type { CasterSphere } from './caustics.js';
4
+ /** Per-target photon splats and independent floating-point batch accumulation. */
5
+ export declare class WGPUCausticLightPass {
6
+ private readonly device;
7
+ private readonly photonMapping;
8
+ private distribution?;
9
+ private emissionGroups;
10
+ private casterCount;
11
+ private choiceCount;
12
+ private pipeline?;
13
+ private readonly outputs;
14
+ private readonly uniform;
15
+ private readonly layout;
16
+ private readonly accumulate;
17
+ constructor(device: GPUDevice, photonMapping?: boolean);
18
+ /** Compiles an emitter for one trace pipeline's layouts; select it with use(). */
19
+ prepare(source: string, groups: GPUBindGroupLayout[], bindless?: boolean): Promise<GPUComputePipeline>;
20
+ use(pipeline: GPUComputePipeline): void;
21
+ setDistribution(spheres: readonly CasterSphere[], lights: {
22
+ data: Float32Array;
23
+ count: number;
24
+ }): void;
25
+ get(target: object): GPUBuffer | undefined;
26
+ bytes(target: object): number;
27
+ release(target: object): void;
28
+ encode(encoder: GPUCommandEncoder, groups: GPUBindGroup[], target: object, options: {
29
+ photonMapping?: boolean;
30
+ photonDirections?: GPUTexture;
31
+ querySet?: GPUQuerySet;
32
+ resourceTable?: ResourceTable;
33
+ width: number;
34
+ height: number;
35
+ clear: boolean;
36
+ run: boolean;
37
+ photons: number;
38
+ batch: number;
39
+ viewProjection: Float32Array | Float64Array | number[];
40
+ casterSphere: readonly number[];
41
+ cameraScale: number;
42
+ casterCount?: number;
43
+ choiceCount?: number;
44
+ orthographic?: boolean;
45
+ }): void;
46
+ emit(encoder: GPUCommandEncoder, groups: GPUBindGroup[], storage: GPUBuffer | GPUTexture, options: Parameters<WGPUCausticLightPass['encode']>[3]): void;
47
+ dispose(): void;
48
+ }