rayzee 9.4.1 → 9.5.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.
- package/README.md +226 -25
- package/dist/ActiveColor-YvuQq44O.js +13 -0
- package/dist/ArchiveImporter-xuUJiklP.js +4301 -0
- package/dist/AssetConfig-DSEntE65.js +30 -0
- package/dist/BidirectionalIntegrator-C5PKjJoT.js +934 -0
- package/dist/ColorManagement-CheBCPaW.js +1488 -0
- package/dist/EngineDefaults-DH3bI5t-.js +844 -0
- package/dist/EngineEvents-Ci8dVWCP.js +73 -0
- package/dist/EngineIssues-CIZnXHsF.js +72 -0
- package/dist/FileFormats-sPGJeCRc.js +102 -0
- package/dist/Logger-BnHghprG.js +97 -0
- package/dist/{NeuralRetouch-vkdXXyK2.js → NeuralRetouch-CW11yLZ_.js} +8 -6
- package/dist/{NeuralSuperRes-FVqRJKQV.js → NeuralSuperRes-BekaecYg.js} +55 -120
- package/dist/PathTracer-Ccl9KOuF.js +29729 -0
- package/dist/PhysicalSky-Dv2PMFGW.js +1219 -0
- package/dist/RayzeeRenderer-BQxnzCTD.js +3542 -0
- package/dist/SolarLimb-ken-JbDK.js +721 -0
- package/dist/ToneMapGPU-BHi5JzIq.js +177 -0
- package/dist/ViewTransforms-D0rTLBsX.js +255 -0
- package/dist/WorkingMatrix-C6y233hT.js +27 -0
- package/dist/ZipReader-gDSWr0I5.js +98 -0
- package/dist/addons/archives.es.js +3 -0
- package/dist/addons/bidirectional.es.js +2 -0
- package/dist/addons/color.es.js +3 -0
- package/dist/addons/formats.es.js +2 -0
- package/dist/addons/physical-sky.es.js +2 -0
- package/dist/addons/storage.es.js +3 -0
- package/dist/archiveFormats-BZw7TiDp.js +75 -0
- package/dist/identity-DrQsGT2o.js +39 -0
- package/dist/openStorage-DwcBRUj7.js +820 -0
- package/dist/rayzee-core.es.js +12 -0
- package/dist/rayzee.es.js +2266 -44125
- package/dist/rayzee.umd.js +485 -473
- package/dist/sceneCachePolicy-BmwYOYDu.js +183 -0
- package/dist/shared-BGBcSxBQ.js +17 -0
- package/package.json +23 -2
- package/src/Color/ActiveColor.js +34 -0
- package/src/Color/BasicColor.js +147 -0
- package/src/Color/ColorManagement.js +7 -31
- package/src/EngineDefaults.js +23 -14
- package/src/EngineEvents.js +2 -0
- package/src/EngineIssues.js +1 -0
- package/src/PathTracerApp.js +617 -4016
- package/src/Pipeline/PipelineContext.js +0 -4
- package/src/Platform.js +36 -0
- package/src/Processor/ArchiveCache.js +1 -1
- package/src/Processor/ArchiveImporter.js +1259 -0
- package/src/Processor/AssetLoader.js +322 -1746
- package/src/Processor/AtmosphereModel.js +1 -2
- package/src/Processor/BVHBuilder.js +4 -95
- package/src/Processor/EnvironmentExactTable.js +187 -0
- package/src/Processor/EquirectHDRInfo.js +30 -223
- package/src/Processor/FileFormats.js +116 -0
- package/src/Processor/GLTFDecoders.js +85 -0
- package/src/Processor/GLTFDiffuseTransmission.js +63 -0
- package/src/Processor/GeometryExtractor.js +12 -1
- package/src/Processor/IESParser.js +47 -35
- package/src/Processor/KernelManager.js +35 -2
- package/src/Processor/MaterialPacking.js +8 -7
- package/src/Processor/PBRT/PBRTMaterials.js +129 -41
- package/src/Processor/PBRT/PBRTParser.js +30 -17
- package/src/Processor/PBRT/PBRTSceneBuilder.js +548 -37
- package/src/Processor/PBRT/PBRTTextureBake.js +154 -0
- package/src/Processor/PBRT/PFM.js +59 -0
- package/src/Processor/PackedRayBuffer.js +116 -9
- package/src/Processor/ParallelBVHBuilder.js +3 -6
- package/src/Processor/PhysicalSky.js +5 -4
- package/src/Processor/PlatformImageLoader.js +50 -6
- package/src/Processor/QueueManager.js +12 -3
- package/src/Processor/ReinsertionOptimizer.js +2 -2
- package/src/Processor/SceneProcessor.js +15 -55
- package/src/Processor/ShaderBuilder.js +6 -16
- package/src/Processor/SimpleSky.js +1 -62
- package/src/Processor/SolarLimb.js +3 -0
- package/src/Processor/TextureCreator.js +1 -1
- package/src/Processor/Workers/BVHSubtreeWorker.js +1 -34
- package/src/Processor/Workers/BVHWorker.js +5 -18
- package/src/Processor/Workers/CDFWorker.js +6 -183
- package/src/Processor/archiveFormats.js +7 -0
- package/src/Processor/utils.js +2 -1
- package/src/RayzeeRenderer.js +3902 -0
- package/src/RenderSettings.js +49 -41
- package/src/Stages/ASVGF.js +5 -7
- package/src/Stages/AutoExposure.js +3 -12
- package/src/Stages/Compositor.js +8 -23
- package/src/Stages/NRD.js +9 -2
- package/src/Stages/NormalDepth.js +9 -6
- package/src/Stages/PathTracer.js +254 -38
- package/src/Stages/PathTracerStage.js +11 -16
- package/src/Storage/BLASCache.js +1 -1
- package/src/Storage/CDFCache.js +18 -17
- package/src/Storage/DownloadCache.js +1 -1
- package/src/Storage/SceneGraphCodec.js +46 -3
- package/src/Storage/SpillStore.js +1 -1
- package/src/Storage/StorageManager.js +2 -4
- package/src/Storage/areas.js +4 -0
- package/src/TSL/BVHTraversal.js +62 -24
- package/src/TSL/Bidirectional.js +204 -0
- package/src/TSL/BidirectionalLamps.js +132 -0
- package/src/TSL/Clearcoat.js +15 -6
- package/src/TSL/Common.js +19 -14
- package/src/TSL/ConnectKernel.js +147 -0
- package/src/TSL/Debugger.js +1 -1
- package/src/TSL/Displacement.js +4 -3
- package/src/TSL/EmissiveSampling.js +64 -17
- package/src/TSL/Environment.js +77 -106
- package/src/TSL/EnvironmentCDF.js +85 -39
- package/src/TSL/ExtendKernel.js +8 -3
- package/src/TSL/FinalWriteKernel.js +4 -4
- package/src/TSL/GenerateKernel.js +18 -4
- package/src/TSL/HitFacet.js +35 -5
- package/src/TSL/LightBVHSampling.js +40 -9
- package/src/TSL/LightGenerateKernel.js +293 -0
- package/src/TSL/LightGuide.js +198 -0
- package/src/TSL/LightSplatKernel.js +165 -0
- package/src/TSL/LightsCore.js +13 -38
- package/src/TSL/LightsDirect.js +28 -29
- package/src/TSL/LightsIndirect.js +3 -1
- package/src/TSL/LightsSampling.js +90 -38
- package/src/TSL/MaterialEvaluation.js +113 -31
- package/src/TSL/MaterialProperties.js +44 -17
- package/src/TSL/MaterialTransmission.js +52 -47
- package/src/TSL/MergeKernel.js +218 -0
- package/src/TSL/PathTracerCore.js +65 -29
- package/src/TSL/Random.js +4 -0
- package/src/TSL/SceneResources.js +51 -0
- package/src/TSL/ShadeKernel.js +881 -103
- package/src/TSL/Struct.js +10 -0
- package/src/TSL/Sun.js +1 -1
- package/src/TSL/TextureSampling.js +65 -60
- package/src/addons/archives.js +14 -0
- package/src/addons/bidirectional.js +13 -0
- package/src/addons/color.js +32 -0
- package/src/addons/formats.js +16 -0
- package/src/addons/physicalSky.js +14 -0
- package/src/addons/storage.js +19 -0
- package/src/core.js +35 -0
- package/src/index.js +3 -1
- package/src/integrators/BidirectionalIntegrator.js +832 -0
- package/src/managers/EnvironmentManager.js +94 -91
- package/src/managers/MaterialDataManager.js +42 -0
- package/src/managers/UniformManager.js +0 -1
- package/dist/ToneMapGPU-DKQM1pMd.js +0 -552
- package/dist/rolldown-runtime-CAFD8bLK.js +0 -11
- package/src/Processor/TreeletOptimizer.js +0 -574
package/src/Stages/PathTracer.js
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
import { uniform, texture, storage } from 'three/tsl';
|
|
8
8
|
import { gpuOnlyStorageAttribute } from '../TSL/patches.js';
|
|
9
9
|
import { PathTracerStage } from './PathTracerStage.js';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
PackedRayBuffer, GBUFFER_STRIDE, RAY_STRIDE, HIT_STRIDE, freeStorageAttribute,
|
|
12
|
+
} from '../Processor/PackedRayBuffer.js';
|
|
11
13
|
import { QueueManager, COUNTER, ENERGY_SCALE } from '../Processor/QueueManager.js';
|
|
12
14
|
import { VRAMTracker } from '../Processor/VRAMTracker.js';
|
|
13
15
|
import { KernelManager } from '../Processor/KernelManager.js';
|
|
@@ -17,13 +19,14 @@ import { buildShadeKernel, SHADE_WG_SIZE } from '../TSL/ShadeKernel.js';
|
|
|
17
19
|
import { buildCompactKernel, buildCompactSubgroupKernel, COMPACT_WG_SIZE } from '../TSL/CompactKernel.js';
|
|
18
20
|
import { buildFinalWriteKernel, FINALWRITE_WG_SIZE } from '../TSL/FinalWriteKernel.js';
|
|
19
21
|
import { buildDebugKernel, DEBUG_WG_SIZE } from '../TSL/DebugKernel.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
+
import { buildBucketTextureNodes, refreshBucketTextureNodes } from '../TSL/TextureSampling.js';
|
|
23
|
+
import { withSceneResources, MATERIAL_LAYERS } from '../TSL/SceneResources.js';
|
|
22
24
|
import {
|
|
23
25
|
buildResetGlobalHistKernel, buildGlobalHistKernel, buildGlobalPrefixKernel, buildGlobalScatterKernel,
|
|
24
26
|
SORT_GLOBAL_WG_SIZE, SORT_GLOBAL_MAX_BINS,
|
|
25
27
|
} from '../TSL/SortGlobalKernels.js';
|
|
26
28
|
import { ENGINE_DEFAULTS, MAX_STORAGE_TEXTURE_SIZE } from '../EngineDefaults.js';
|
|
29
|
+
import { ISSUE_CODES } from '../EngineIssues.js';
|
|
27
30
|
import { createLogger, fmt } from '../utils/Logger.js';
|
|
28
31
|
import { deviceMemoryGB } from '../Processor/HostMemory.js';
|
|
29
32
|
import {
|
|
@@ -33,11 +36,11 @@ import {
|
|
|
33
36
|
const log = createLogger( 'wavefront' );
|
|
34
37
|
|
|
35
38
|
// Shared by the 1D index-list kernels built inline below.
|
|
36
|
-
const LIST_WG_SIZE = 256;
|
|
39
|
+
export const LIST_WG_SIZE = 256;
|
|
37
40
|
|
|
38
41
|
// Resized per bounce iteration, each from its own registered workgroup size. Unregistered entries
|
|
39
42
|
// (the sort passes when _sortMaterials is off) are skipped by setDispatchForCount.
|
|
40
|
-
const BOUNCE_KERNELS = [ 'extend', 'shade', 'globalHist', 'globalScatter', 'compact', 'compactCopyback' ];
|
|
43
|
+
export const BOUNCE_KERNELS = [ 'extend', 'shade', 'connect', 'merge', 'globalHist', 'globalScatter', 'compact', 'compactCopyback', 'lightCopyback' ];
|
|
41
44
|
|
|
42
45
|
export class PathTracer extends PathTracerStage {
|
|
43
46
|
|
|
@@ -58,6 +61,9 @@ export class PathTracer extends PathTracerStage {
|
|
|
58
61
|
this._convDebugSource = null; // memoized handle set for the Compositor's convergence overlay
|
|
59
62
|
this._dilateFrozenUniform = uniform( 1, 'int' ); // 1 = dilate (default); 0 = plain per-pixel freeze
|
|
60
63
|
this._wavefrontReady = false;
|
|
64
|
+
// The background compile of the kernels last built (_compileKernels), and its build's number.
|
|
65
|
+
this._kernelsCompiling = null;
|
|
66
|
+
this._kernelGeneration = 0;
|
|
61
67
|
|
|
62
68
|
// Aux MRT (normalDepth + albedo) feeds only the denoiser/OIDN. When no denoiser is active the
|
|
63
69
|
// wavefront skips those writes (Generate/Shade G-buffer + FinalWrite stores). Gated by a live
|
|
@@ -142,6 +148,18 @@ export class PathTracer extends PathTracerStage {
|
|
|
142
148
|
this._chunkRows = 0; // rows per chunk = floor(B / renderWidth), clamped ≥1
|
|
143
149
|
this._numChunks = 1; // ceil(renderHeight / chunkRows)
|
|
144
150
|
|
|
151
|
+
// Outputs a later stage asked for (requestOutput), compiled into Shade only while asked.
|
|
152
|
+
this._outputs = new Map();
|
|
153
|
+
this._outputsChanged = false;
|
|
154
|
+
// The material layers the kernels were compiled with (_layersToCompile).
|
|
155
|
+
this._compiledLayers = null;
|
|
156
|
+
|
|
157
|
+
// Integrators other than the path tracer's own, by name (registerIntegrator); the chosen one's instance, or
|
|
158
|
+
// null for plain path tracing, which builds exactly the unidirectional kernels.
|
|
159
|
+
this._integratorFactories = new Map();
|
|
160
|
+
this._integratorInstances = new Map();
|
|
161
|
+
this._integrator = null;
|
|
162
|
+
|
|
145
163
|
// VRAM accounting — providers are thunks reading CURRENT live resources,
|
|
146
164
|
// so they survive buffer/texture reallocation (resize, scene/material reload).
|
|
147
165
|
this.vramTracker = new VRAMTracker( this.renderer );
|
|
@@ -159,10 +177,13 @@ export class PathTracer extends PathTracerStage {
|
|
|
159
177
|
t.register( 'rays', () => {
|
|
160
178
|
|
|
161
179
|
const a = this._packedBuffers?._attrs;
|
|
162
|
-
return a ? [ a.ray, a.
|
|
180
|
+
return a ? [ a.ray, a.hit ] : null;
|
|
163
181
|
|
|
164
182
|
} );
|
|
165
183
|
|
|
184
|
+
// An integrator's own buffers (a light vertex cache rides in the hit buffer, under 'rays')
|
|
185
|
+
t.register( 'integrator', () => this._integrator?.gpuResources() ?? null );
|
|
186
|
+
|
|
166
187
|
// Queue indices + atomic counters
|
|
167
188
|
t.register( 'queues', () => {
|
|
168
189
|
|
|
@@ -236,14 +257,112 @@ export class PathTracer extends PathTracerStage {
|
|
|
236
257
|
|
|
237
258
|
}
|
|
238
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Asks for an extra per-pixel output, compiled in only while someone asks for it; the kernels rebuild before the
|
|
262
|
+
* next frame. `'gBuffer'`: the denoisers' normal/depth (`pathtracer:normalDepth`) and albedo (`pathtracer:albedo`),
|
|
263
|
+
* written while setAuxGBufferEnabled( true ). `'hitDistance'`: the first bounce's segment plus any alpha-skip run,
|
|
264
|
+
* at camera depth 1, as `encode( distance, viewZ )` returns it — a [0, 1] value, in `pathtracer:albedo.w`; it
|
|
265
|
+
* brings the G-buffer with it.
|
|
266
|
+
* @param {'gBuffer'|'hitDistance'} name
|
|
267
|
+
* @param {{encode?: function(Node, Node): Node}} [options]
|
|
268
|
+
* @returns {function(): void} withdraws the request
|
|
269
|
+
*/
|
|
270
|
+
requestOutput( name, options = {} ) {
|
|
271
|
+
|
|
272
|
+
this._outputs.set( name, options );
|
|
273
|
+
this._outputsChanged = true;
|
|
274
|
+
|
|
275
|
+
return () => {
|
|
276
|
+
|
|
277
|
+
if ( this._outputs.get( name ) !== options ) return;
|
|
278
|
+
this._outputs.delete( name );
|
|
279
|
+
this._outputsChanged = true;
|
|
280
|
+
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Makes an integrator choosable by name. `create( pathTracer )` makes its instance, once, which then takes the
|
|
287
|
+
* integrator hooks this class calls (see BidirectionalIntegrator); one class may answer several names.
|
|
288
|
+
* @param {string|string[]} names
|
|
289
|
+
* @param {function(PathTracer): Object} create
|
|
290
|
+
*/
|
|
291
|
+
registerIntegrator( names, create ) {
|
|
292
|
+
|
|
293
|
+
for ( const name of [ names ].flat() ) this._integratorFactories.set( name, create );
|
|
294
|
+
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Switching rebuilds the kernels: only an integrator's own bind its buffers. 'path' is the path tracer's own;
|
|
299
|
+
* the others must have been registered (rayzee/addons/bidirectional: 'bidirectional', 'vcm').
|
|
300
|
+
* @param {string} name
|
|
301
|
+
*/
|
|
302
|
+
setIntegrator( name ) {
|
|
303
|
+
|
|
304
|
+
let next = null;
|
|
305
|
+
if ( name !== 'path' ) {
|
|
306
|
+
|
|
307
|
+
const create = this._integratorFactories.get( name );
|
|
308
|
+
if ( ! create ) {
|
|
309
|
+
|
|
310
|
+
this.issues?.record( ISSUE_CODES.CAPABILITY_MISSING, `integrator "${name}" is not installed: pathTracer.registerIntegrator(), or rayzee/addons/bidirectional`, { capability: name } );
|
|
311
|
+
return;
|
|
312
|
+
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
next = this._integratorInstances.get( create );
|
|
316
|
+
if ( ! next ) this._integratorInstances.set( create, next = create( this ) );
|
|
317
|
+
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if ( next === this._integrator && ( ! next || next.name === name ) ) return;
|
|
321
|
+
if ( this._integrator && this._integrator !== next ) this._integrator.dispose();
|
|
322
|
+
next?.select( name );
|
|
323
|
+
this._integrator = next;
|
|
324
|
+
this._pathBudget = 0;
|
|
325
|
+
|
|
326
|
+
if ( this._packedBuffers && this.materialData?.materialCount > 0 ) {
|
|
327
|
+
|
|
328
|
+
if ( this._kernelManager ) this._kernelManager.dispose();
|
|
329
|
+
this._wavefrontReady = false;
|
|
330
|
+
this._buildWavefrontKernels();
|
|
331
|
+
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
get integrator() {
|
|
337
|
+
|
|
338
|
+
return this._integrator?.name ?? 'path';
|
|
339
|
+
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** The chosen integrator's instance — its controls, e.g. setStrategy() — or null for plain path tracing. */
|
|
343
|
+
get activeIntegrator() {
|
|
344
|
+
|
|
345
|
+
return this._integrator;
|
|
346
|
+
|
|
347
|
+
}
|
|
348
|
+
|
|
239
349
|
render( context ) {
|
|
240
350
|
|
|
241
351
|
// Kernels not built yet (first frame / mid-resize) — skip until ready.
|
|
242
352
|
if ( ! this.isReady || ! this._wavefrontReady ) return;
|
|
243
353
|
|
|
244
354
|
// The packed light buffer was grow-reallocated at runtime (emissive set grew) or a light list grew —
|
|
245
|
-
// the compiled kernels still bind the old one, so rebuild before rendering.
|
|
246
|
-
|
|
355
|
+
// the compiled kernels still bind the old one, so rebuild before rendering. Likewise a changed output request.
|
|
356
|
+
// A layer some material now uses is compiled in at once; one nothing uses any more waits for the next build.
|
|
357
|
+
if ( this._materialFeaturesChanged ) {
|
|
358
|
+
|
|
359
|
+
this._materialFeaturesChanged = false;
|
|
360
|
+
const needed = this._layersToCompile();
|
|
361
|
+
if ( MATERIAL_LAYERS.some( ( layer ) => needed[ layer ] && ! this._compiledLayers?.[ layer ] ) ) this._outputsChanged = true;
|
|
362
|
+
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if ( this._lightBufferRealloc || this._outputsChanged ) {
|
|
247
366
|
|
|
248
367
|
if ( this._kernelManager ) this._kernelManager.dispose();
|
|
249
368
|
this._wavefrontReady = false;
|
|
@@ -292,7 +411,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
292
411
|
}
|
|
293
412
|
|
|
294
413
|
this._handleResize();
|
|
295
|
-
this.
|
|
414
|
+
this.resetHistoryOnRenderModeChange( renderMode );
|
|
296
415
|
|
|
297
416
|
// Full-frame render is always a complete cycle (PER_CYCLE stages gate on this).
|
|
298
417
|
if ( context ) context.setState( 'tileRenderingComplete', true );
|
|
@@ -390,6 +509,9 @@ export class PathTracer extends PathTracerStage {
|
|
|
390
509
|
: Math.min( this._lastBounceCountsBudget, this._lastBounceCountsLoopBound ) )
|
|
391
510
|
: 0;
|
|
392
511
|
|
|
512
|
+
// An integrator's light subpaths first, through the same pool; every camera chunk then connects to them.
|
|
513
|
+
const integrator = this._integrator?.beginFrame( loopBound ) ? this._integrator : null;
|
|
514
|
+
|
|
393
515
|
// Blender-style row-band streaming: the fixed-budget path pool processes the image in bands of ≤ chunkRows
|
|
394
516
|
// rows (one chunk when the frame fits the budget → identical to the pre-chunking path). See spec.
|
|
395
517
|
for ( let chunkIndex = 0, rowBase = 0; rowBase < frameHeight; rowBase += chunkRows, chunkIndex ++ ) {
|
|
@@ -492,7 +614,9 @@ export class PathTracer extends PathTracerStage {
|
|
|
492
614
|
|
|
493
615
|
}
|
|
494
616
|
|
|
617
|
+
integrator?.beforeShade();
|
|
495
618
|
km.dispatch( 'shade' ); // shade thread 0 folds resetActiveCounter (zeroes ACTIVE_RAY_COUNT before compact)
|
|
619
|
+
integrator?.afterShade( km );
|
|
496
620
|
km.dispatch( 'compact' );
|
|
497
621
|
if ( useFunctionalCompaction ) {
|
|
498
622
|
|
|
@@ -521,6 +645,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
521
645
|
|
|
522
646
|
}
|
|
523
647
|
|
|
648
|
+
integrator?.resolve( km );
|
|
524
649
|
km.dispatch( 'finalWrite' );
|
|
525
650
|
|
|
526
651
|
}
|
|
@@ -723,17 +848,50 @@ export class PathTracer extends PathTracerStage {
|
|
|
723
848
|
}
|
|
724
849
|
|
|
725
850
|
/**
|
|
726
|
-
* While a lockstep readback is due and has not landed, render() traces
|
|
727
|
-
* before the next frame. Null otherwise.
|
|
851
|
+
* While the kernels compile in the background, or a lockstep readback is due and has not landed, render() traces
|
|
852
|
+
* nothing: await this before the next frame. Null otherwise.
|
|
728
853
|
* @returns {?Promise<void>}
|
|
729
854
|
*/
|
|
730
855
|
readbackWait() {
|
|
731
856
|
|
|
857
|
+
if ( this._kernelsCompiling ) return this._kernelsCompiling;
|
|
732
858
|
const pending = this._lockstepRead;
|
|
733
859
|
return pending && ! pending.apply && this.frameCount >= pending.due ? pending.read : null;
|
|
734
860
|
|
|
735
861
|
}
|
|
736
862
|
|
|
863
|
+
/**
|
|
864
|
+
* Compiles the kernels just built without blocking the page. Until they are ready render() traces nothing and the
|
|
865
|
+
* canvas keeps its last frame; every driver loop awaits readbackWait(), which returns this. A build started
|
|
866
|
+
* meanwhile supersedes it. A failed background compile — and every compile in Node — leaves each kernel to compile
|
|
867
|
+
* at its first dispatch.
|
|
868
|
+
*/
|
|
869
|
+
_compileKernels() {
|
|
870
|
+
|
|
871
|
+
const generation = ++ this._kernelGeneration;
|
|
872
|
+
if ( ! KernelManager.canCompileInBackground ) {
|
|
873
|
+
|
|
874
|
+
this._kernelsCompiling = null;
|
|
875
|
+
this._wavefrontReady = true;
|
|
876
|
+
return;
|
|
877
|
+
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
const kernels = this._kernelManager;
|
|
881
|
+
this.emit( 'pathtracer:compiling', { compiling: true } );
|
|
882
|
+
this._kernelsCompiling = kernels.compile()
|
|
883
|
+
.catch( ( error ) => log.warn( `background kernel compile failed — compiling at first dispatch: ${error?.message ?? error}` ) )
|
|
884
|
+
.then( () => {
|
|
885
|
+
|
|
886
|
+
if ( generation !== this._kernelGeneration ) return;
|
|
887
|
+
this._kernelsCompiling = null;
|
|
888
|
+
this._wavefrontReady = true;
|
|
889
|
+
this.emit( 'pathtracer:compiling', { compiling: false } );
|
|
890
|
+
|
|
891
|
+
} );
|
|
892
|
+
|
|
893
|
+
}
|
|
894
|
+
|
|
737
895
|
/**
|
|
738
896
|
* Per-pixel convergence state for the Compositor's debug overlay: the buffers FinalWrite maintains
|
|
739
897
|
* plus the uniforms needed to re-derive its predicate. Read-only — the overlay never writes back.
|
|
@@ -798,11 +956,12 @@ export class PathTracer extends PathTracerStage {
|
|
|
798
956
|
}
|
|
799
957
|
|
|
800
958
|
// Aux MRT (normalDepth/albedo) is needed only by the denoiser/OIDN; DenoisingManager calls this to
|
|
801
|
-
// turn the wavefront's aux writes on/off.
|
|
802
|
-
// no kernel rebuild, no UI freeze.
|
|
959
|
+
// turn the wavefront's aux writes on/off. The first call that turns them on compiles them in (requestOutput,
|
|
960
|
+
// kept for good); after that it is a live uniform, so toggling is a value flip — no kernel rebuild, no UI freeze.
|
|
803
961
|
setAuxGBufferEnabled( enabled ) {
|
|
804
962
|
|
|
805
963
|
enabled = !! enabled;
|
|
964
|
+
if ( enabled && ! this._outputs.has( 'gBuffer' ) ) this.requestOutput( 'gBuffer' );
|
|
806
965
|
if ( this._auxGBufferEnabled === enabled ) return;
|
|
807
966
|
this._auxGBufferEnabled = enabled;
|
|
808
967
|
this._auxGBufferUniform.value = enabled ? 1 : 0;
|
|
@@ -888,7 +1047,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
888
1047
|
|
|
889
1048
|
_bounceLoopBound() {
|
|
890
1049
|
|
|
891
|
-
|
|
1050
|
+
// Camera paths take one segment past their last bounce (ShadeKernel, EMISSION_ONLY).
|
|
1051
|
+
return this.maxBounces.value + this.transmissiveBounces.value + this.maxSubsurfaceSteps.value + 1;
|
|
892
1052
|
|
|
893
1053
|
}
|
|
894
1054
|
|
|
@@ -942,12 +1102,13 @@ export class PathTracer extends PathTracerStage {
|
|
|
942
1102
|
const budget = this.maxBounces.value;
|
|
943
1103
|
const measuredLoopBound = this._bounceLoopBound();
|
|
944
1104
|
const n = this._queueManager.MAX_BOUNCE_SNAPSHOTS;
|
|
1105
|
+
const lightKey = this._integrator?.curveKey ?? null;
|
|
945
1106
|
this.renderer.getArrayBufferAsync( attr ).then( ( buf ) => {
|
|
946
1107
|
|
|
947
1108
|
// Drop counts measured at a now-stale generation (a resize or camera move happened mid-flight).
|
|
948
1109
|
// A surviving readback was initiated while settled (init is skipped mid-motion) and no motion
|
|
949
1110
|
// happened before it resolved, so its counts match the current view — safe to size from.
|
|
950
|
-
if ( gen === this._readbackGeneration ) this._applyBounceCounts( buf, budget, measuredLoopBound, n );
|
|
1111
|
+
if ( gen === this._readbackGeneration ) this._applyBounceCounts( buf, budget, measuredLoopBound, n, lightKey );
|
|
951
1112
|
|
|
952
1113
|
this._readbackPending = false;
|
|
953
1114
|
|
|
@@ -971,7 +1132,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
971
1132
|
// Full-FRAME pixel count (CONVERGED_COUNT sums across all chunks) — not _wfMaxRayCount, which
|
|
972
1133
|
// after the chunk loop holds only the last band's pixel count.
|
|
973
1134
|
const total = this._wfRenderWidth.value * this._wfRenderHeight.value;
|
|
974
|
-
this.renderer.getArrayBufferAsync( cAttr ).then( ( buf ) => {
|
|
1135
|
+
this.renderer.getArrayBufferAsync( cAttr, null, 0, COUNTER.COUNT * 4 ).then( ( buf ) => {
|
|
975
1136
|
|
|
976
1137
|
if ( cgen === this._readbackGeneration && total > 0 ) this._applyCounters( buf, total );
|
|
977
1138
|
|
|
@@ -1004,17 +1165,18 @@ export class PathTracer extends PathTracerStage {
|
|
|
1004
1165
|
const loopBound = this._bounceLoopBound();
|
|
1005
1166
|
const n = this._queueManager.MAX_BOUNCE_SNAPSHOTS;
|
|
1006
1167
|
const total = this._wfRenderWidth.value * this._wfRenderHeight.value;
|
|
1168
|
+
const lightKey = this._integrator?.curveKey ?? null;
|
|
1007
1169
|
|
|
1008
1170
|
const entry = { due: this.frameCount + this._readbackEveryNFrames, read: null, apply: null };
|
|
1009
1171
|
entry.read = Promise.all( [
|
|
1010
1172
|
this.renderer.getArrayBufferAsync( bounceAttr ),
|
|
1011
|
-
this.renderer.getArrayBufferAsync( counterAttr ),
|
|
1173
|
+
this.renderer.getArrayBufferAsync( counterAttr, null, 0, COUNTER.COUNT * 4 ),
|
|
1012
1174
|
] ).then( ( [ bounceBuf, counterBuf ] ) => {
|
|
1013
1175
|
|
|
1014
1176
|
entry.apply = () => {
|
|
1015
1177
|
|
|
1016
1178
|
if ( gen !== this._readbackGeneration ) return;
|
|
1017
|
-
this._applyBounceCounts( bounceBuf, budget, loopBound, n );
|
|
1179
|
+
this._applyBounceCounts( bounceBuf, budget, loopBound, n, lightKey );
|
|
1018
1180
|
if ( total > 0 ) this._applyCounters( counterBuf, total );
|
|
1019
1181
|
|
|
1020
1182
|
};
|
|
@@ -1030,11 +1192,13 @@ export class PathTracer extends PathTracerStage {
|
|
|
1030
1192
|
|
|
1031
1193
|
}
|
|
1032
1194
|
|
|
1033
|
-
_applyBounceCounts( buf, budget, loopBound, n ) {
|
|
1195
|
+
_applyBounceCounts( buf, budget, loopBound, n, lightKey = null ) {
|
|
1034
1196
|
|
|
1035
1197
|
const all = new Uint32Array( buf.slice( 0 ) );
|
|
1036
1198
|
this._lastBounceCounts = all.subarray( 0, n );
|
|
1037
1199
|
this._lastBounceEnergy = all.subarray( n, 2 * n );
|
|
1200
|
+
// An integrator's light pass keeps its own curve after the camera's.
|
|
1201
|
+
this._integrator?.applyLightCurve( all.subarray( 2 * n, 3 * n ), all.subarray( 3 * n, 4 * n ), lightKey );
|
|
1038
1202
|
this._lastBounceCountsBudget = budget;
|
|
1039
1203
|
this._lastBounceCountsLoopBound = loopBound;
|
|
1040
1204
|
this._curveSizingValid = true;
|
|
@@ -1148,19 +1312,23 @@ export class PathTracer extends PathTracerStage {
|
|
|
1148
1312
|
// any resolution through this pool, so a small B just means more row-bands (works on weak / small-VRAM GPUs).
|
|
1149
1313
|
_computePathBudget() {
|
|
1150
1314
|
|
|
1151
|
-
if ( this._pathBudgetOverride > 0 ) return this._pathBudgetOverride;
|
|
1152
|
-
|
|
1153
1315
|
const RAY_BYTES = RAY_STRIDE * 16;
|
|
1154
|
-
const
|
|
1316
|
+
const HIT_BYTES = ( this._integrator?.hitStride ?? HIT_STRIDE ) * 16;
|
|
1317
|
+
const bytesPerPath = RAY_BYTES + HIT_BYTES + GBUFFER_STRIDE * 16
|
|
1155
1318
|
+ 4 + 4 /* activeIndices A/B */ + 4;
|
|
1156
1319
|
|
|
1157
1320
|
const limits = this.renderer?.backend?.device?.limits;
|
|
1158
1321
|
const maxBinding = limits?.maxStorageBufferBindingSize || ( 128 * 1024 * 1024 );
|
|
1159
1322
|
const maxBuffer = limits?.maxBufferSize || maxBinding;
|
|
1160
|
-
|
|
1161
|
-
const bByBinding = Math.floor( ( maxBinding * 0.9 ) / RAY_BYTES );
|
|
1162
1323
|
const deviceMemBytes = deviceMemoryGB( this.hostMemoryGB ).gb * 1024 * 1024 * 1024;
|
|
1163
|
-
|
|
1324
|
+
|
|
1325
|
+
// An integrator's light vertex cache shares the hit buffer's binding with the paths.
|
|
1326
|
+
const cacheBytes = this._integrator?.cacheBytes( maxBinding, deviceMemBytes ) ?? 0;
|
|
1327
|
+
|
|
1328
|
+
if ( this._pathBudgetOverride > 0 ) return this._pathBudgetOverride;
|
|
1329
|
+
|
|
1330
|
+
const bByBinding = Math.floor( Math.min( ( maxBinding * 0.9 ) / RAY_BYTES, ( maxBinding * 0.9 - cacheBytes ) / HIT_BYTES ) );
|
|
1331
|
+
const poolVramBudget = Math.min( deviceMemBytes * 0.25, maxBuffer * 4 ) - cacheBytes;
|
|
1164
1332
|
const bByVram = Math.floor( poolVramBudget / bytesPerPath );
|
|
1165
1333
|
|
|
1166
1334
|
const MIN_B = 512 * 512;
|
|
@@ -1219,6 +1387,22 @@ export class PathTracer extends PathTracerStage {
|
|
|
1219
1387
|
|
|
1220
1388
|
}
|
|
1221
1389
|
|
|
1390
|
+
/** The material layers the scene uses; bidirectional leaves diffuse transmission out (its paths do not cross surfaces). */
|
|
1391
|
+
_layersToCompile() {
|
|
1392
|
+
|
|
1393
|
+
const layers = this.materialData.materialLayers();
|
|
1394
|
+
if ( this._integrator ) layers.diffuseTransmission = false;
|
|
1395
|
+
return layers;
|
|
1396
|
+
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
/** Whether the kernels write the G-buffer: asked for directly, or for the hit distance that rides in it. */
|
|
1400
|
+
get _gBufferCompiled() {
|
|
1401
|
+
|
|
1402
|
+
return this._outputs.has( 'gBuffer' ) || this._outputs.has( 'hitDistance' );
|
|
1403
|
+
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1222
1406
|
_buildWavefrontKernels() {
|
|
1223
1407
|
|
|
1224
1408
|
const texNodes = this.shaderBuilder.getSceneTextureNodes();
|
|
@@ -1226,6 +1410,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1226
1410
|
|
|
1227
1411
|
// A fresh build binds the current lightStorageAttr — any pending realloc is covered.
|
|
1228
1412
|
this._lightBufferRealloc = false;
|
|
1413
|
+
this._outputsChanged = false;
|
|
1414
|
+
this._integrator?.beforeKernelBuild();
|
|
1229
1415
|
|
|
1230
1416
|
const w = this.storageTextures.renderWidth;
|
|
1231
1417
|
const h = this.storageTextures.renderHeight;
|
|
@@ -1242,13 +1428,14 @@ export class PathTracer extends PathTracerStage {
|
|
|
1242
1428
|
|
|
1243
1429
|
// Per-path buffers (RAY/HIT/rng) sized to the budget B and indexed by LOCAL slot r ∈ [0,B). _cap = B is
|
|
1244
1430
|
// baked into the SoA stride but never changes with resolution, so this build happens once (model load).
|
|
1431
|
+
const lightVertices = this._integrator?.lightVertices ?? 0;
|
|
1245
1432
|
if ( ! this._packedBuffers ) {
|
|
1246
1433
|
|
|
1247
|
-
this._packedBuffers = new PackedRayBuffer( B, this.renderer );
|
|
1434
|
+
this._packedBuffers = new PackedRayBuffer( B, this.renderer, lightVertices );
|
|
1248
1435
|
|
|
1249
1436
|
} else {
|
|
1250
1437
|
|
|
1251
|
-
this._packedBuffers.resize( B );
|
|
1438
|
+
this._packedBuffers.resize( B, lightVertices );
|
|
1252
1439
|
|
|
1253
1440
|
}
|
|
1254
1441
|
|
|
@@ -1286,6 +1473,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1286
1473
|
|
|
1287
1474
|
}
|
|
1288
1475
|
|
|
1476
|
+
this._integrator?.allocate( maxPixels );
|
|
1477
|
+
|
|
1289
1478
|
const m2RW = storage( this._m2Attr, 'float' );
|
|
1290
1479
|
const streakRW = storage( this._streakAttr, 'uint' );
|
|
1291
1480
|
const streakRO = storage( this._streakAttr, 'uint' ).toReadOnly();
|
|
@@ -1404,6 +1593,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1404
1593
|
transmissiveBounces: this.transmissiveBounces,
|
|
1405
1594
|
transparentBackground: this.transparentBackground,
|
|
1406
1595
|
auxGBufferEnabled: this._auxGBufferUniform,
|
|
1596
|
+
gBuffer: this._gBufferCompiled,
|
|
1597
|
+
bidirectional: this._integrator?.uniforms ?? null,
|
|
1407
1598
|
};
|
|
1408
1599
|
const genFn = buildGenerateKernel( genParams );
|
|
1409
1600
|
this._kernelManager.register( 'generate',
|
|
@@ -1597,13 +1788,21 @@ export class PathTracer extends PathTracerStage {
|
|
|
1597
1788
|
const _mat = this.materialData;
|
|
1598
1789
|
const _env = this.environment;
|
|
1599
1790
|
// Consolidated size-bucket nodes (K sRGB + K linear). Empty buckets get placeholders so
|
|
1600
|
-
// every runtime branch references a valid node.
|
|
1601
|
-
// the Shade/Debug graphs are built so they bake in these (per-pipeline) nodes.
|
|
1791
|
+
// every runtime branch references a valid node.
|
|
1602
1792
|
const freshSrgbBuckets = buildBucketTextureNodes( _mat.srgbBuckets );
|
|
1603
1793
|
const freshLinearBuckets = buildBucketTextureNodes( _mat.linearBuckets );
|
|
1604
|
-
|
|
1605
|
-
// Alpha-cutout shadow rays sample albedo (sRGB pool)
|
|
1606
|
-
|
|
1794
|
+
// This renderer's resources, in the build context of each kernel that samples them (SceneResources.js).
|
|
1795
|
+
// Alpha-cutout shadow rays sample albedo (sRGB pool).
|
|
1796
|
+
const resources = {
|
|
1797
|
+
srgbBuckets: freshSrgbBuckets,
|
|
1798
|
+
linearBuckets: freshLinearBuckets,
|
|
1799
|
+
shadowAlbedoMaps: freshSrgbBuckets,
|
|
1800
|
+
goboMaps: texNodes.goboMapsTex,
|
|
1801
|
+
iesProfiles: texNodes.iesProfilesTex,
|
|
1802
|
+
alphaShadows: this.uniforms.get( 'enableAlphaShadows' ),
|
|
1803
|
+
materialLayers: this._compiledLayers = this._layersToCompile(),
|
|
1804
|
+
};
|
|
1805
|
+
const own = ( call ) => withSceneResources( call, resources );
|
|
1607
1806
|
const freshEnvTex = _env.environmentTexture ? texture( _env.environmentTexture ) : texNodes.envTex;
|
|
1608
1807
|
|
|
1609
1808
|
this._wfTexNodes = {
|
|
@@ -1680,7 +1879,6 @@ export class PathTracer extends PathTracerStage {
|
|
|
1680
1879
|
|
|
1681
1880
|
const shadeFn = buildShadeKernel( {
|
|
1682
1881
|
gBufferRW,
|
|
1683
|
-
envCompensationDelta: this.envCompensationDelta,
|
|
1684
1882
|
bvhBuffer: freshBvh,
|
|
1685
1883
|
triangleBuffer: freshTri,
|
|
1686
1884
|
materialBuffer: freshMat,
|
|
@@ -1732,7 +1930,6 @@ export class PathTracer extends PathTracerStage {
|
|
|
1732
1930
|
emissiveVec4Offset: this.emissiveVec4Offset,
|
|
1733
1931
|
emissiveTotalPower: this.emissiveTotalPower,
|
|
1734
1932
|
emissiveBoost: this.emissiveBoost,
|
|
1735
|
-
totalTriangleCount: this.totalTriangleCount,
|
|
1736
1933
|
enableEmissiveTriangleSampling: this.enableEmissiveTriangleSampling,
|
|
1737
1934
|
lightBVHNodeCount: this.lightBVHNodeCount,
|
|
1738
1935
|
reverseMapVec4Offset: this.reverseMapVec4Offset,
|
|
@@ -1740,13 +1937,17 @@ export class PathTracer extends PathTracerStage {
|
|
|
1740
1937
|
maxRayCount: this._wfMaxRayCount,
|
|
1741
1938
|
chunkRowBase: this._wfChunkRowBase,
|
|
1742
1939
|
auxGBufferEnabled: this._auxGBufferUniform,
|
|
1940
|
+
gBuffer: this._gBufferCompiled,
|
|
1743
1941
|
hasSun: this.hasSun,
|
|
1744
1942
|
sunDirection: this.sunDirection,
|
|
1745
1943
|
sunRadiance: this.sunRadiance,
|
|
1746
1944
|
sunParams: this.sunParams,
|
|
1945
|
+
bidirectional: this._integrator?.uniforms ?? null,
|
|
1946
|
+
hitDistanceEncode: this._outputs.get( 'hitDistance' )?.encode ?? null,
|
|
1947
|
+
materialLayers: this._compiledLayers,
|
|
1747
1948
|
} );
|
|
1748
1949
|
this._kernelManager.register( 'shade',
|
|
1749
|
-
shadeFn().compute(
|
|
1950
|
+
own( shadeFn() ).compute(
|
|
1750
1951
|
[ Math.ceil( maxRays / SHADE_WG_SIZE ), 1, 1 ],
|
|
1751
1952
|
[ SHADE_WG_SIZE, 1, 1 ]
|
|
1752
1953
|
)
|
|
@@ -1812,6 +2013,11 @@ export class PathTracer extends PathTracerStage {
|
|
|
1812
2013
|
copyFn().compute( [ Math.ceil( maxRays / LIST_WG_SIZE ), 1, 1 ], [ LIST_WG_SIZE, 1, 1 ] )
|
|
1813
2014
|
);
|
|
1814
2015
|
|
|
2016
|
+
this._integrator?.registerKernels( {
|
|
2017
|
+
km: this._kernelManager, qm, pb, counters, bounceCountsBuf, wfCurrentBounce, copyReadB, copyWriteA, maxRays, w, own,
|
|
2018
|
+
freshLight, freshTri, freshBvh, freshMat, freshEnvTex, freshEnvCDF,
|
|
2019
|
+
} );
|
|
2020
|
+
|
|
1815
2021
|
const fwFn = buildFinalWriteKernel( {
|
|
1816
2022
|
rayBufferRO: pb.rayBuffer.ro,
|
|
1817
2023
|
gBufferRO,
|
|
@@ -1834,6 +2040,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1834
2040
|
renderHeight: this._wfRenderHeight,
|
|
1835
2041
|
visMode: this.visMode,
|
|
1836
2042
|
auxGBufferEnabled: this._auxGBufferUniform,
|
|
2043
|
+
gBuffer: this._gBufferCompiled,
|
|
1837
2044
|
cleanAuxNormalEnabled: this._cleanAuxNormalUniform,
|
|
1838
2045
|
m2BufferRW: m2RW,
|
|
1839
2046
|
useAdaptiveSampling: this.useAdaptiveSampling,
|
|
@@ -1893,14 +2100,16 @@ export class PathTracer extends PathTracerStage {
|
|
|
1893
2100
|
debugVisScale: this.debugVisScale,
|
|
1894
2101
|
frame: this.frame,
|
|
1895
2102
|
} );
|
|
2103
|
+
// Only the debug views dispatch it, so it compiles when one is first chosen.
|
|
1896
2104
|
this._kernelManager.register( 'debug',
|
|
1897
|
-
debugFn().compute(
|
|
2105
|
+
own( debugFn() ).compute(
|
|
1898
2106
|
[ Math.ceil( w / DEBUG_WG_SIZE ), Math.ceil( h / DEBUG_WG_SIZE ), 1 ],
|
|
1899
2107
|
[ DEBUG_WG_SIZE, DEBUG_WG_SIZE, 1 ]
|
|
1900
|
-
)
|
|
2108
|
+
),
|
|
2109
|
+
{ eager: false },
|
|
1901
2110
|
);
|
|
1902
2111
|
|
|
1903
|
-
this.
|
|
2112
|
+
this._compileKernels();
|
|
1904
2113
|
|
|
1905
2114
|
const bufferBytes = ( this._packedBuffers?.totalBytes ?? 0 ) + ( this._queueManager?.totalBytes ?? 0 );
|
|
1906
2115
|
|
|
@@ -1909,6 +2118,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1909
2118
|
`${fmt.mb( bufferBytes )} wavefront buffers`,
|
|
1910
2119
|
`budget ${fmt.n( B )} paths`,
|
|
1911
2120
|
this._numChunks > 1 ? `${this._numChunks} chunks of ≤${this._chunkRows} rows` : null,
|
|
2121
|
+
this._integrator?.describe() ?? null,
|
|
1912
2122
|
] ) );
|
|
1913
2123
|
|
|
1914
2124
|
}
|
|
@@ -1941,6 +2151,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1941
2151
|
const km = this._kernelManager;
|
|
1942
2152
|
km.setDispatchForGrid( 'generate', w, rows );
|
|
1943
2153
|
km.setDispatchForGrid( 'finalWrite', w, rows );
|
|
2154
|
+
km.setDispatchForGrid( 'splatResolve', w, rows );
|
|
1944
2155
|
km.setDispatchForCount( 'initActiveIndices', chunkPixels );
|
|
1945
2156
|
km.setDispatchForCount( 'buildActivePixels', chunkPixels );
|
|
1946
2157
|
|
|
@@ -1958,6 +2169,9 @@ export class PathTracer extends PathTracerStage {
|
|
|
1958
2169
|
this._m2Attr?.dispose?.();
|
|
1959
2170
|
this._streakAttr?.dispose?.();
|
|
1960
2171
|
this._frozenMaskAttr?.dispose?.();
|
|
2172
|
+
for ( const integrator of this._integratorInstances.values() ) integrator.dispose();
|
|
2173
|
+
this._integratorInstances.clear();
|
|
2174
|
+
this._integrator = null;
|
|
1961
2175
|
this._packedBuffers = null;
|
|
1962
2176
|
this._queueManager = null;
|
|
1963
2177
|
this._kernelManager = null;
|
|
@@ -1967,6 +2181,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1967
2181
|
this._frozenMaskAttr = null;
|
|
1968
2182
|
this._convDebugSource = null;
|
|
1969
2183
|
this._wavefrontReady = false;
|
|
2184
|
+
this._kernelGeneration ++;
|
|
2185
|
+
this._kernelsCompiling = null;
|
|
1970
2186
|
|
|
1971
2187
|
}
|
|
1972
2188
|
|
|
@@ -53,8 +53,7 @@ const BVH_VEC4_PER_NODE = 4;
|
|
|
53
53
|
* Events emitted:
|
|
54
54
|
* - pathtracer:frameComplete - When a frame finishes rendering
|
|
55
55
|
* - camera:moved - When camera position/orientation changes
|
|
56
|
-
* -
|
|
57
|
-
* - asvgf:updateParameters - Update ASVGF parameters
|
|
56
|
+
* - pipeline:historyReset - temporal history from before is not comparable (render mode change)
|
|
58
57
|
*
|
|
59
58
|
* Textures published to context:
|
|
60
59
|
* - pathtracer:color - Main color output
|
|
@@ -113,6 +112,13 @@ export class PathTracerStage extends RenderStage {
|
|
|
113
112
|
// Initialize material data manager
|
|
114
113
|
this.materialData = new MaterialDataManager( this.sdfs );
|
|
115
114
|
this.materialData.callbacks.onReset = () => this.reset();
|
|
115
|
+
// A material edit can switch the diffuse transmission lobe on or off, which the shade kernel compiles in.
|
|
116
|
+
this.materialData.callbacks.onMaterialFeaturesChanged = () => {
|
|
117
|
+
|
|
118
|
+
this._materialFeaturesChanged = true;
|
|
119
|
+
|
|
120
|
+
};
|
|
121
|
+
|
|
116
122
|
// Material edits patch the per-triangle flags lane in the CPU records (`_triangleRecords`
|
|
117
123
|
// when chunked, `_triangleFlat` otherwise — not sdfs.triangleData, which the PathTracerApp
|
|
118
124
|
// build path never fills). The flags live in the shade rows, so only those go up again.
|
|
@@ -375,16 +381,6 @@ export class PathTracerStage extends RenderStage {
|
|
|
375
381
|
|
|
376
382
|
} );
|
|
377
383
|
|
|
378
|
-
this.on( 'pathtracer:setCompletionThreshold', ( data ) => {
|
|
379
|
-
|
|
380
|
-
if ( data && data.threshold !== undefined ) {
|
|
381
|
-
|
|
382
|
-
this.completionThreshold = data.threshold;
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
} );
|
|
387
|
-
|
|
388
384
|
}
|
|
389
385
|
|
|
390
386
|
// ===== PUBLIC API METHODS =====
|
|
@@ -542,7 +538,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
542
538
|
this.performanceMonitor?.reset();
|
|
543
539
|
|
|
544
540
|
// lastRenderMode is deliberately NOT invalidated here — clearing it made
|
|
545
|
-
//
|
|
541
|
+
// resetHistoryOnRenderModeChange see a phantom mode change 50 ms after every reset, wiping
|
|
546
542
|
// ASVGF's history. A real mode change is still caught by the renderMode comparison.
|
|
547
543
|
this.lastInteractionModeState = false;
|
|
548
544
|
|
|
@@ -1420,7 +1416,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
1420
1416
|
|
|
1421
1417
|
// ===== ASVGF DENOISING MANAGEMENT =====
|
|
1422
1418
|
|
|
1423
|
-
|
|
1419
|
+
resetHistoryOnRenderModeChange( renderMode ) {
|
|
1424
1420
|
|
|
1425
1421
|
if ( renderMode !== this.lastRenderMode ) {
|
|
1426
1422
|
|
|
@@ -1440,8 +1436,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
1440
1436
|
// History from the previous mode is not comparable. temporalAlpha is NOT
|
|
1441
1437
|
// touched here — it is owned by ASVGF_QUALITY_PRESETS, and overwriting it
|
|
1442
1438
|
// with a hardcoded value meant `medium` and `high` never took effect.
|
|
1443
|
-
this.emit( '
|
|
1444
|
-
this.emit( 'denoiser:reset' );
|
|
1439
|
+
this.emit( 'pipeline:historyReset' );
|
|
1445
1440
|
|
|
1446
1441
|
}
|
|
1447
1442
|
|
package/src/Storage/BLASCache.js
CHANGED