rayzee 10.0.0 → 11.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +252 -44
- package/dist/ActiveColor-YvuQq44O.js +13 -0
- package/dist/ArchiveImporter-Hn35o6Z5.js +5145 -0
- package/dist/AssetConfig-DSEntE65.js +30 -0
- package/dist/BidirectionalIntegrator-CBw8hkeu.js +946 -0
- package/dist/BufferLayout-D_IBo2ci.js +150 -0
- package/dist/ColorManagement-oeEk7oSu.js +1488 -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-dDDGj9Av.js +97 -0
- package/dist/{NeuralRetouch-CYgkQY8Z.js → NeuralRetouch-BzNpiVHZ.js} +8 -6
- package/dist/{NeuralSuperRes-PkgDLQcD.js → NeuralSuperRes-Bk7bHg2B.js} +55 -120
- package/dist/PathTracer-72XufKAr.js +29976 -0
- package/dist/PhysicalSky-BgjdV88k.js +1219 -0
- package/dist/RayzeeRenderer-1QRO97eq.js +3551 -0
- package/dist/SolarLimb-CPaeZVwz.js +721 -0
- package/dist/ToneMapGPU-CjU3osDd.js +177 -0
- package/dist/ViewTransforms-CYN7bq2w.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-tnAoUL1j.js +94 -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 +2551 -44024
- package/dist/rayzee.umd.js +528 -487
- package/dist/sceneCachePolicy-C67jbci-.js +443 -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/Color/ViewTransforms.js +5 -1
- package/src/EngineDefaults.js +62 -1029
- package/src/EngineEvents.js +2 -0
- package/src/EngineIssues.js +2 -0
- package/src/Headless.js +6 -5
- package/src/Passes/AIUpscaler.js +58 -141
- package/src/Passes/OIDNDenoiser.js +92 -65
- package/src/Passes/OIDNTemporalHistory.js +1 -1
- package/src/PathTracerApp.js +620 -4026
- package/src/Pipeline/PipelineContext.js +0 -4
- package/src/Platform.js +36 -0
- package/src/Processor/ArchiveCache.js +20 -7
- package/src/Processor/ArchiveImporter.js +1265 -0
- package/src/Processor/ArchiveReader.js +22 -4
- package/src/Processor/AssetLoader.js +327 -1763
- package/src/Processor/AtmosphereModel.js +1 -2
- package/src/Processor/BVHBuilder.js +14 -126
- package/src/Processor/BVHLeafFold.js +4 -6
- package/src/Processor/BVHRefitter.js +67 -46
- package/src/Processor/BufferLayout.js +291 -0
- package/src/Processor/EmissiveTriangleBuilder.js +1 -1
- 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 +15 -5
- package/src/Processor/HostMemory.js +7 -1
- package/src/Processor/IESParser.js +47 -35
- package/src/Processor/InstanceTable.js +1 -1
- package/src/Processor/KernelManager.js +35 -2
- package/src/Processor/MaterialPacking.js +10 -8
- package/src/Processor/PBRT/PBRTMaterials.js +254 -42
- package/src/Processor/PBRT/PBRTParser.js +49 -19
- package/src/Processor/PBRT/PBRTScattering.js +93 -0
- package/src/Processor/PBRT/PBRTSceneBuilder.js +1050 -75
- package/src/Processor/PBRT/PBRTTextureBake.js +179 -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 +39 -5
- package/src/Processor/ReinsertionOptimizer.js +2 -2
- package/src/Processor/SceneMetadata.js +30 -5
- package/src/Processor/SceneProcessor.js +53 -62
- package/src/Processor/ShaderBuilder.js +6 -16
- package/src/Processor/SimpleSky.js +1 -62
- package/src/Processor/SolarLimb.js +3 -0
- package/src/Processor/SplitBLAS.js +1 -1
- package/src/Processor/StorageTexturePool.js +22 -1
- package/src/Processor/TLASBuilder.js +1 -3
- package/src/Processor/TextureBuckets.js +237 -0
- package/src/Processor/TextureCreator.js +181 -8
- package/src/Processor/ToneMapGPU.js +64 -15
- package/src/Processor/Workers/BVHRefitWorker.js +5 -2
- 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/Workers/TexturesWorker.js +103 -18
- package/src/Processor/archiveFormats.js +7 -0
- package/src/Processor/utils.js +2 -1
- package/src/RayzeeRenderer.js +3900 -0
- package/src/RenderSettings.js +68 -62
- package/src/Stages/ASVGF.js +13 -14
- package/src/Stages/AutoExposure.js +17 -17
- package/src/Stages/BilateralFilter.js +2 -1
- package/src/Stages/Compositor.js +8 -23
- package/src/Stages/DenoiserSettings.js +182 -0
- package/src/Stages/EdgeFilter.js +2 -1
- package/src/Stages/MotionVector.js +1 -1
- package/src/Stages/NRD.js +11 -5
- package/src/Stages/NormalDepth.js +12 -8
- package/src/Stages/PathTracer.js +336 -43
- package/src/Stages/PathTracerStage.js +69 -66
- package/src/Stages/Variance.js +1 -1
- 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 +45 -9
- package/src/Storage/areas.js +4 -0
- package/src/TSL/BVHTraversal.js +50 -25
- package/src/TSL/Bidirectional.js +208 -0
- package/src/TSL/BidirectionalLamps.js +132 -0
- package/src/TSL/Clearcoat.js +15 -6
- package/src/TSL/Common.js +20 -15
- package/src/TSL/ConnectKernel.js +167 -0
- package/src/TSL/Debugger.js +1 -1
- package/src/TSL/Displacement.js +4 -3
- package/src/TSL/EmissiveSampling.js +65 -18
- 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 +180 -0
- package/src/TSL/LightVisibility.js +111 -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 +239 -51
- 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 +224 -0
- package/src/TSL/PathTracerCore.js +65 -29
- package/src/TSL/Random.js +5 -1
- package/src/TSL/SceneResources.js +51 -0
- package/src/TSL/ShadeKernel.js +985 -101
- package/src/TSL/Struct.js +10 -0
- package/src/TSL/Sun.js +1 -1
- package/src/TSL/TextureSampling.js +66 -61
- 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 +31 -0
- package/src/index.js +13 -23
- package/src/integrators/BidirectionalIntegrator.js +838 -0
- package/src/managers/AnimationManager.js +88 -6
- package/src/managers/CameraManager.js +103 -46
- package/src/managers/DenoisingManager.js +14 -10
- package/src/managers/EnvironmentManager.js +125 -103
- package/src/managers/GoboManager.js +9 -0
- package/src/managers/MaterialDataManager.js +48 -37
- package/src/managers/UniformManager.js +32 -10
- package/dist/ToneMapGPU-B6XIe3DU.js +0 -544
- package/dist/rolldown-runtime-CAFD8bLK.js +0 -11
- package/src/Processor/TreeletOptimizer.js +0 -574
package/src/Stages/PathTracer.js
CHANGED
|
@@ -7,23 +7,28 @@
|
|
|
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';
|
|
14
16
|
import { buildGenerateKernel, GENERATE_WG_SIZE } from '../TSL/GenerateKernel.js';
|
|
15
17
|
import { buildExtendKernel, EXTEND_WG_SIZE } from '../TSL/ExtendKernel.js';
|
|
16
18
|
import { buildShadeKernel, SHADE_WG_SIZE } from '../TSL/ShadeKernel.js';
|
|
19
|
+
import { buildVisibilityFoldKernel, buildVisibilityClearKernel } from '../TSL/LightVisibility.js';
|
|
17
20
|
import { buildCompactKernel, buildCompactSubgroupKernel, COMPACT_WG_SIZE } from '../TSL/CompactKernel.js';
|
|
18
21
|
import { buildFinalWriteKernel, FINALWRITE_WG_SIZE } from '../TSL/FinalWriteKernel.js';
|
|
19
22
|
import { buildDebugKernel, DEBUG_WG_SIZE } from '../TSL/DebugKernel.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
23
|
+
import { buildBucketTextureNodes, refreshBucketTextureNodes } from '../TSL/TextureSampling.js';
|
|
24
|
+
import { withSceneResources, MATERIAL_LAYERS } from '../TSL/SceneResources.js';
|
|
22
25
|
import {
|
|
23
26
|
buildResetGlobalHistKernel, buildGlobalHistKernel, buildGlobalPrefixKernel, buildGlobalScatterKernel,
|
|
24
27
|
SORT_GLOBAL_WG_SIZE, SORT_GLOBAL_MAX_BINS,
|
|
25
28
|
} from '../TSL/SortGlobalKernels.js';
|
|
26
|
-
import { ENGINE_DEFAULTS
|
|
29
|
+
import { ENGINE_DEFAULTS } from '../EngineDefaults.js';
|
|
30
|
+
import { MAX_STORAGE_TEXTURE_SIZE } from '../Processor/StorageTexturePool.js';
|
|
31
|
+
import { ISSUE_CODES } from '../EngineIssues.js';
|
|
27
32
|
import { createLogger, fmt } from '../utils/Logger.js';
|
|
28
33
|
import { deviceMemoryGB } from '../Processor/HostMemory.js';
|
|
29
34
|
import {
|
|
@@ -33,11 +38,14 @@ import {
|
|
|
33
38
|
const log = createLogger( 'wavefront' );
|
|
34
39
|
|
|
35
40
|
// Shared by the 1D index-list kernels built inline below.
|
|
36
|
-
const LIST_WG_SIZE = 256;
|
|
41
|
+
export const LIST_WG_SIZE = 256;
|
|
37
42
|
|
|
38
43
|
// Resized per bounce iteration, each from its own registered workgroup size. Unregistered entries
|
|
39
44
|
// (the sort passes when _sortMaterials is off) are skipped by setDispatchForCount.
|
|
40
|
-
const
|
|
45
|
+
const PICKED_SHADOW_RAYS = [ 'two', 'one' ];
|
|
46
|
+
const SHADOW_RAY_MODES = [ 'all', ...PICKED_SHADOW_RAYS ];
|
|
47
|
+
|
|
48
|
+
export const BOUNCE_KERNELS = [ 'extend', 'shade', 'connect', 'merge', 'globalHist', 'globalScatter', 'compact', 'compactCopyback', 'lightCopyback' ];
|
|
41
49
|
|
|
42
50
|
export class PathTracer extends PathTracerStage {
|
|
43
51
|
|
|
@@ -58,6 +66,9 @@ export class PathTracer extends PathTracerStage {
|
|
|
58
66
|
this._convDebugSource = null; // memoized handle set for the Compositor's convergence overlay
|
|
59
67
|
this._dilateFrozenUniform = uniform( 1, 'int' ); // 1 = dilate (default); 0 = plain per-pixel freeze
|
|
60
68
|
this._wavefrontReady = false;
|
|
69
|
+
// The background compile of the kernels last built (_compileKernels), and its build's number.
|
|
70
|
+
this._kernelsCompiling = null;
|
|
71
|
+
this._kernelGeneration = 0;
|
|
61
72
|
|
|
62
73
|
// Aux MRT (normalDepth + albedo) feeds only the denoiser/OIDN. When no denoiser is active the
|
|
63
74
|
// wavefront skips those writes (Generate/Shade G-buffer + FinalWrite stores). Gated by a live
|
|
@@ -77,9 +88,10 @@ export class PathTracer extends PathTracerStage {
|
|
|
77
88
|
// CPU sizes per-bounce kernels from last frame's survivor curve; kernels bound on ENTERING_COUNT so over-sizing is safe. (indirect dispatch not viable — three.js doesn't sync compute-written indirect buffers across submissions)
|
|
78
89
|
this._useDynamicDispatch = true;
|
|
79
90
|
|
|
80
|
-
// Global material-coherence sort:
|
|
91
|
+
// Global material-coherence sort: the wavefrontSortMaterials setting, applied per build above 8 materials.
|
|
81
92
|
// Reorders entering rays into material-pure workgroups before Shade; runs under dynamic dispatch
|
|
82
93
|
// (compact reads the unsorted active list, so the survivor set is unchanged). Measured −8% at 1024²/8b.
|
|
94
|
+
this.sortMaterials = options.sortMaterials ?? ENGINE_DEFAULTS.wavefrontSortMaterials;
|
|
83
95
|
this._sortMaterials = false;
|
|
84
96
|
|
|
85
97
|
// Flag-gated off: perf-neutral vs atomic-append and adds a 'subgroups' feature dependency.
|
|
@@ -118,6 +130,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
118
130
|
// so when one lands cannot change the image. { due, read, apply } while one is in flight.
|
|
119
131
|
this._lockstep = false;
|
|
120
132
|
this._lockstepRead = null;
|
|
133
|
+
this._accumulationLockstep = false;
|
|
121
134
|
|
|
122
135
|
// Tier-2: last settled active-pixel count (maxRays − frozen), sizes next frame's bounce-0 grid.
|
|
123
136
|
// 0 until a settled readback lands (and on reset/camera-move/resize) → grid stays full-size until then.
|
|
@@ -141,6 +154,21 @@ export class PathTracer extends PathTracerStage {
|
|
|
141
154
|
this._chunkRows = 0; // rows per chunk = floor(B / renderWidth), clamped ≥1
|
|
142
155
|
this._numChunks = 1; // ceil(renderHeight / chunkRows)
|
|
143
156
|
|
|
157
|
+
// Outputs a later stage asked for (requestOutput), compiled into Shade only while asked.
|
|
158
|
+
this._outputs = new Map();
|
|
159
|
+
this._outputsChanged = false;
|
|
160
|
+
// The material layers the kernels were compiled with (_layersToCompile).
|
|
161
|
+
this._compiledLayers = null;
|
|
162
|
+
this._shadowRays = 'all';
|
|
163
|
+
this._compiledPick = null;
|
|
164
|
+
this._learnsVisibility = false;
|
|
165
|
+
|
|
166
|
+
// Integrators other than the path tracer's own, by name (registerIntegrator); the chosen one's instance, or
|
|
167
|
+
// null for plain path tracing, which builds exactly the unidirectional kernels.
|
|
168
|
+
this._integratorFactories = new Map();
|
|
169
|
+
this._integratorInstances = new Map();
|
|
170
|
+
this._integrator = null;
|
|
171
|
+
|
|
144
172
|
// VRAM accounting — providers are thunks reading CURRENT live resources,
|
|
145
173
|
// so they survive buffer/texture reallocation (resize, scene/material reload).
|
|
146
174
|
this.vramTracker = new VRAMTracker( this.renderer );
|
|
@@ -158,10 +186,13 @@ export class PathTracer extends PathTracerStage {
|
|
|
158
186
|
t.register( 'rays', () => {
|
|
159
187
|
|
|
160
188
|
const a = this._packedBuffers?._attrs;
|
|
161
|
-
return a ? [ a.ray, a.
|
|
189
|
+
return a ? [ a.ray, a.hit ] : null;
|
|
162
190
|
|
|
163
191
|
} );
|
|
164
192
|
|
|
193
|
+
// An integrator's own buffers (a light vertex cache rides in the hit buffer, under 'rays')
|
|
194
|
+
t.register( 'integrator', () => this._integrator?.gpuResources() ?? null );
|
|
195
|
+
|
|
165
196
|
// Queue indices + atomic counters
|
|
166
197
|
t.register( 'queues', () => {
|
|
167
198
|
|
|
@@ -235,14 +266,152 @@ export class PathTracer extends PathTracerStage {
|
|
|
235
266
|
|
|
236
267
|
}
|
|
237
268
|
|
|
269
|
+
/**
|
|
270
|
+
* Asks for an extra per-pixel output, compiled in only while someone asks for it; the kernels rebuild before the
|
|
271
|
+
* next frame. `'gBuffer'`: the denoisers' normal/depth (`pathtracer:normalDepth`) and albedo (`pathtracer:albedo`),
|
|
272
|
+
* written while setAuxGBufferEnabled( true ). `'hitDistance'`: the first bounce's segment plus any alpha-skip run,
|
|
273
|
+
* at camera depth 1, as `encode( distance, viewZ )` returns it — a [0, 1] value, in `pathtracer:albedo.w`; it
|
|
274
|
+
* brings the G-buffer with it.
|
|
275
|
+
* @param {'gBuffer'|'hitDistance'} name
|
|
276
|
+
* @param {{encode?: function(Node, Node): Node}} [options]
|
|
277
|
+
* @returns {function(): void} withdraws the request
|
|
278
|
+
*/
|
|
279
|
+
requestOutput( name, options = {} ) {
|
|
280
|
+
|
|
281
|
+
this._outputs.set( name, options );
|
|
282
|
+
this._outputsChanged = true;
|
|
283
|
+
|
|
284
|
+
return () => {
|
|
285
|
+
|
|
286
|
+
if ( this._outputs.get( name ) !== options ) return;
|
|
287
|
+
this._outputs.delete( name );
|
|
288
|
+
this._outputsChanged = true;
|
|
289
|
+
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Makes an integrator choosable by name. `create( pathTracer )` makes its instance, once, which then takes the
|
|
296
|
+
* integrator hooks this class calls (see BidirectionalIntegrator); one class may answer several names.
|
|
297
|
+
* @param {string|string[]} names
|
|
298
|
+
* @param {function(PathTracer): Object} create
|
|
299
|
+
*/
|
|
300
|
+
registerIntegrator( names, create ) {
|
|
301
|
+
|
|
302
|
+
for ( const name of [ names ].flat() ) this._integratorFactories.set( name, create );
|
|
303
|
+
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Switching rebuilds the kernels: only an integrator's own bind its buffers. 'path' is the path tracer's own;
|
|
308
|
+
* the others must have been registered (rayzee/addons/bidirectional: 'bidirectional', 'vcm').
|
|
309
|
+
* @param {string} name
|
|
310
|
+
*/
|
|
311
|
+
setIntegrator( name ) {
|
|
312
|
+
|
|
313
|
+
let next = null;
|
|
314
|
+
if ( name !== 'path' ) {
|
|
315
|
+
|
|
316
|
+
const create = this._integratorFactories.get( name );
|
|
317
|
+
if ( ! create ) {
|
|
318
|
+
|
|
319
|
+
this.issues?.record( ISSUE_CODES.CAPABILITY_MISSING, `integrator "${name}" is not installed: pathTracer.registerIntegrator(), or rayzee/addons/bidirectional`, { capability: name } );
|
|
320
|
+
return;
|
|
321
|
+
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
next = this._integratorInstances.get( create );
|
|
325
|
+
if ( ! next ) this._integratorInstances.set( create, next = create( this ) );
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if ( next === this._integrator && ( ! next || next.name === name ) ) return;
|
|
330
|
+
if ( this._integrator && this._integrator !== next ) this._integrator.dispose();
|
|
331
|
+
next?.select( name );
|
|
332
|
+
this._integrator = next;
|
|
333
|
+
this._pathBudget = 0;
|
|
334
|
+
|
|
335
|
+
if ( this._packedBuffers && this.materialData?.materialCount > 0 ) {
|
|
336
|
+
|
|
337
|
+
if ( this._kernelManager ) this._kernelManager.dispose();
|
|
338
|
+
this._wavefrontReady = false;
|
|
339
|
+
this._buildWavefrontKernels();
|
|
340
|
+
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Shadow rays a hit for the lamps, sky, sun and emitters: 'all', one per kind; 'two', the strongest and one picked
|
|
347
|
+
* from the rest; 'one', one picked, by unshadowed light and where each kind gets through. Rebuilds the kernels
|
|
348
|
+
* before the next frame; bidirectional integrators ignore it.
|
|
349
|
+
* @param {'all'|'two'|'one'} mode
|
|
350
|
+
*/
|
|
351
|
+
setShadowRays( mode ) {
|
|
352
|
+
|
|
353
|
+
if ( ! SHADOW_RAY_MODES.includes( mode ) ) {
|
|
354
|
+
|
|
355
|
+
log.warn( `shadowRays: unknown mode "${mode}", using 'all'` );
|
|
356
|
+
mode = 'all';
|
|
357
|
+
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if ( this._shadowRays === mode ) return;
|
|
361
|
+
this._shadowRays = mode;
|
|
362
|
+
this._outputsChanged = true;
|
|
363
|
+
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* The lightPick variant to compile, or null for a ray per light kind: also when the scene has no more kinds than the
|
|
368
|
+
* variant traces rays, where it would only add its bookkeeping.
|
|
369
|
+
*/
|
|
370
|
+
_pickedShadowRays() {
|
|
371
|
+
|
|
372
|
+
if ( this._integrator || ! PICKED_SHADOW_RAYS.includes( this._shadowRays ) ) return null;
|
|
373
|
+
const environment = this.enableEnvironment.value > 0;
|
|
374
|
+
const lamps = this.numDirectionalLights.value + this.numAreaLights.value + this.numPointLights.value + this.numSpotLights.value;
|
|
375
|
+
const kinds = Number( lamps > 0 )
|
|
376
|
+
+ Number( environment && this.envTotalSum.value > 0 )
|
|
377
|
+
+ Number( environment && this.hasSun.value > 0 )
|
|
378
|
+
+ Number( this.enableEmissiveTriangleSampling.value > 0 && this.emissiveTriangleCount.value > 0 );
|
|
379
|
+
return kinds > ( this._shadowRays === 'two' ? 2 : 1 ) ? this._shadowRays : null;
|
|
380
|
+
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
get integrator() {
|
|
384
|
+
|
|
385
|
+
return this._integrator?.name ?? 'path';
|
|
386
|
+
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** The chosen integrator's instance — its controls, e.g. setStrategy() — or null for plain path tracing. */
|
|
390
|
+
get activeIntegrator() {
|
|
391
|
+
|
|
392
|
+
return this._integrator;
|
|
393
|
+
|
|
394
|
+
}
|
|
395
|
+
|
|
238
396
|
render( context ) {
|
|
239
397
|
|
|
240
398
|
// Kernels not built yet (first frame / mid-resize) — skip until ready.
|
|
241
399
|
if ( ! this.isReady || ! this._wavefrontReady ) return;
|
|
242
400
|
|
|
243
|
-
// The packed light buffer was grow-reallocated at runtime (emissive set grew) —
|
|
244
|
-
// the compiled kernels still bind the old
|
|
245
|
-
|
|
401
|
+
// The packed light buffer was grow-reallocated at runtime (emissive set grew) or a light list grew —
|
|
402
|
+
// the compiled kernels still bind the old one, so rebuild before rendering. Likewise a changed output request.
|
|
403
|
+
// A layer some material now uses is compiled in at once; one nothing uses any more waits for the next build.
|
|
404
|
+
if ( this._materialFeaturesChanged ) {
|
|
405
|
+
|
|
406
|
+
this._materialFeaturesChanged = false;
|
|
407
|
+
const needed = this._layersToCompile();
|
|
408
|
+
if ( MATERIAL_LAYERS.some( ( layer ) => needed[ layer ] && ! this._compiledLayers?.[ layer ] ) ) this._outputsChanged = true;
|
|
409
|
+
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if ( PICKED_SHADOW_RAYS.includes( this._shadowRays ) && this._pickedShadowRays() !== this._compiledPick ) this._outputsChanged = true;
|
|
413
|
+
|
|
414
|
+
if ( this._lightBufferRealloc || this._outputsChanged ) {
|
|
246
415
|
|
|
247
416
|
if ( this._kernelManager ) this._kernelManager.dispose();
|
|
248
417
|
this._wavefrontReady = false;
|
|
@@ -291,7 +460,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
291
460
|
}
|
|
292
461
|
|
|
293
462
|
this._handleResize();
|
|
294
|
-
this.
|
|
463
|
+
this.resetHistoryOnRenderModeChange( renderMode );
|
|
295
464
|
|
|
296
465
|
// Full-frame render is always a complete cycle (PER_CYCLE stages gate on this).
|
|
297
466
|
if ( context ) context.setState( 'tileRenderingComplete', true );
|
|
@@ -320,6 +489,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
320
489
|
this.frame.value = frameValue;
|
|
321
490
|
this.seedFrame.value = this._seedTick ++;
|
|
322
491
|
this.tracedFrames ++;
|
|
492
|
+
if ( ! this._lockstep ) this._accumulationLockstep = false;
|
|
323
493
|
|
|
324
494
|
this._setWfDispatch();
|
|
325
495
|
|
|
@@ -388,6 +558,15 @@ export class PathTracer extends PathTracerStage {
|
|
|
388
558
|
: Math.min( this._lastBounceCountsBudget, this._lastBounceCountsLoopBound ) )
|
|
389
559
|
: 0;
|
|
390
560
|
|
|
561
|
+
// An integrator's light subpaths first, through the same pool; every camera chunk then connects to them.
|
|
562
|
+
const integrator = this._integrator?.beginFrame( loopBound ) ? this._integrator : null;
|
|
563
|
+
// A camera move keeps what was learned (it is kept per place in the scene); a repeatable render starts afresh.
|
|
564
|
+
if ( this._learnsVisibility && frameValue === 0 && ( this._pinSeedToFrame || this._lockstep || ! this.cameraChanged ) ) {
|
|
565
|
+
|
|
566
|
+
km.dispatch( 'visibilityClear' );
|
|
567
|
+
|
|
568
|
+
}
|
|
569
|
+
|
|
391
570
|
// Blender-style row-band streaming: the fixed-budget path pool processes the image in bands of ≤ chunkRows
|
|
392
571
|
// rows (one chunk when the frame fits the budget → identical to the pre-chunking path). See spec.
|
|
393
572
|
for ( let chunkIndex = 0, rowBase = 0; rowBase < frameHeight; rowBase += chunkRows, chunkIndex ++ ) {
|
|
@@ -490,7 +669,9 @@ export class PathTracer extends PathTracerStage {
|
|
|
490
669
|
|
|
491
670
|
}
|
|
492
671
|
|
|
672
|
+
integrator?.beforeShade();
|
|
493
673
|
km.dispatch( 'shade' ); // shade thread 0 folds resetActiveCounter (zeroes ACTIVE_RAY_COUNT before compact)
|
|
674
|
+
integrator?.afterShade( km );
|
|
494
675
|
km.dispatch( 'compact' );
|
|
495
676
|
if ( useFunctionalCompaction ) {
|
|
496
677
|
|
|
@@ -519,10 +700,12 @@ export class PathTracer extends PathTracerStage {
|
|
|
519
700
|
|
|
520
701
|
}
|
|
521
702
|
|
|
703
|
+
integrator?.resolve( km );
|
|
522
704
|
km.dispatch( 'finalWrite' );
|
|
523
705
|
|
|
524
706
|
}
|
|
525
707
|
|
|
708
|
+
if ( this._learnsVisibility ) km.dispatch( 'visibilityFold' );
|
|
526
709
|
this._maybeReadbackCounters();
|
|
527
710
|
|
|
528
711
|
// Skip the normalDepth/albedo copies when aux is off — the wavefront didn't write them and
|
|
@@ -661,6 +844,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
661
844
|
this._convergedFraction = state.convergedFraction ?? 0;
|
|
662
845
|
this._convergedGeometryFraction = state.convergedGeometryFraction ?? 0;
|
|
663
846
|
this.isComplete = false;
|
|
847
|
+
// The survivor curve is not in a checkpoint, so a continuation is not the lockstep render.
|
|
848
|
+
this._accumulationLockstep = false;
|
|
664
849
|
|
|
665
850
|
}
|
|
666
851
|
|
|
@@ -711,18 +896,58 @@ export class PathTracer extends PathTracerStage {
|
|
|
711
896
|
|
|
712
897
|
}
|
|
713
898
|
|
|
899
|
+
/** Whether the current image was traced in lockstep from a reset made in it; with no sample yet, the setting. */
|
|
900
|
+
get accumulationLockstep() {
|
|
901
|
+
|
|
902
|
+
return this.frameCount > 0 ? this._accumulationLockstep : this._lockstep;
|
|
903
|
+
|
|
904
|
+
}
|
|
905
|
+
|
|
714
906
|
/**
|
|
715
|
-
* While a lockstep readback is due and has not landed, render() traces
|
|
716
|
-
* before the next frame. Null otherwise.
|
|
907
|
+
* While the kernels compile in the background, or a lockstep readback is due and has not landed, render() traces
|
|
908
|
+
* nothing: await this before the next frame. Null otherwise.
|
|
717
909
|
* @returns {?Promise<void>}
|
|
718
910
|
*/
|
|
719
911
|
readbackWait() {
|
|
720
912
|
|
|
913
|
+
if ( this._kernelsCompiling ) return this._kernelsCompiling;
|
|
721
914
|
const pending = this._lockstepRead;
|
|
722
915
|
return pending && ! pending.apply && this.frameCount >= pending.due ? pending.read : null;
|
|
723
916
|
|
|
724
917
|
}
|
|
725
918
|
|
|
919
|
+
/**
|
|
920
|
+
* Compiles the kernels just built without blocking the page. Until they are ready render() traces nothing and the
|
|
921
|
+
* canvas keeps its last frame; every driver loop awaits readbackWait(), which returns this. A build started
|
|
922
|
+
* meanwhile supersedes it. A failed background compile — and every compile in Node — leaves each kernel to compile
|
|
923
|
+
* at its first dispatch.
|
|
924
|
+
*/
|
|
925
|
+
_compileKernels() {
|
|
926
|
+
|
|
927
|
+
const generation = ++ this._kernelGeneration;
|
|
928
|
+
if ( ! KernelManager.canCompileInBackground ) {
|
|
929
|
+
|
|
930
|
+
this._kernelsCompiling = null;
|
|
931
|
+
this._wavefrontReady = true;
|
|
932
|
+
return;
|
|
933
|
+
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
const kernels = this._kernelManager;
|
|
937
|
+
this.emit( 'pathtracer:compiling', { compiling: true } );
|
|
938
|
+
this._kernelsCompiling = kernels.compile()
|
|
939
|
+
.catch( ( error ) => log.warn( `background kernel compile failed — compiling at first dispatch: ${error?.message ?? error}` ) )
|
|
940
|
+
.then( () => {
|
|
941
|
+
|
|
942
|
+
if ( generation !== this._kernelGeneration ) return;
|
|
943
|
+
this._kernelsCompiling = null;
|
|
944
|
+
this._wavefrontReady = true;
|
|
945
|
+
this.emit( 'pathtracer:compiling', { compiling: false } );
|
|
946
|
+
|
|
947
|
+
} );
|
|
948
|
+
|
|
949
|
+
}
|
|
950
|
+
|
|
726
951
|
/**
|
|
727
952
|
* Per-pixel convergence state for the Compositor's debug overlay: the buffers FinalWrite maintains
|
|
728
953
|
* plus the uniforms needed to re-derive its predicate. Read-only — the overlay never writes back.
|
|
@@ -787,11 +1012,12 @@ export class PathTracer extends PathTracerStage {
|
|
|
787
1012
|
}
|
|
788
1013
|
|
|
789
1014
|
// Aux MRT (normalDepth/albedo) is needed only by the denoiser/OIDN; DenoisingManager calls this to
|
|
790
|
-
// turn the wavefront's aux writes on/off.
|
|
791
|
-
// no kernel rebuild, no UI freeze.
|
|
1015
|
+
// turn the wavefront's aux writes on/off. The first call that turns them on compiles them in (requestOutput,
|
|
1016
|
+
// kept for good); after that it is a live uniform, so toggling is a value flip — no kernel rebuild, no UI freeze.
|
|
792
1017
|
setAuxGBufferEnabled( enabled ) {
|
|
793
1018
|
|
|
794
1019
|
enabled = !! enabled;
|
|
1020
|
+
if ( enabled && ! this._outputs.has( 'gBuffer' ) ) this.requestOutput( 'gBuffer' );
|
|
795
1021
|
if ( this._auxGBufferEnabled === enabled ) return;
|
|
796
1022
|
this._auxGBufferEnabled = enabled;
|
|
797
1023
|
this._auxGBufferUniform.value = enabled ? 1 : 0;
|
|
@@ -877,7 +1103,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
877
1103
|
|
|
878
1104
|
_bounceLoopBound() {
|
|
879
1105
|
|
|
880
|
-
|
|
1106
|
+
// Camera paths take one segment past their last bounce (ShadeKernel, EMISSION_ONLY).
|
|
1107
|
+
return this.maxBounces.value + this.transmissiveBounces.value + this.maxSubsurfaceSteps.value + 1;
|
|
881
1108
|
|
|
882
1109
|
}
|
|
883
1110
|
|
|
@@ -931,12 +1158,13 @@ export class PathTracer extends PathTracerStage {
|
|
|
931
1158
|
const budget = this.maxBounces.value;
|
|
932
1159
|
const measuredLoopBound = this._bounceLoopBound();
|
|
933
1160
|
const n = this._queueManager.MAX_BOUNCE_SNAPSHOTS;
|
|
1161
|
+
const lightKey = this._integrator?.curveKey ?? null;
|
|
934
1162
|
this.renderer.getArrayBufferAsync( attr ).then( ( buf ) => {
|
|
935
1163
|
|
|
936
1164
|
// Drop counts measured at a now-stale generation (a resize or camera move happened mid-flight).
|
|
937
1165
|
// A surviving readback was initiated while settled (init is skipped mid-motion) and no motion
|
|
938
1166
|
// happened before it resolved, so its counts match the current view — safe to size from.
|
|
939
|
-
if ( gen === this._readbackGeneration ) this._applyBounceCounts( buf, budget, measuredLoopBound, n );
|
|
1167
|
+
if ( gen === this._readbackGeneration ) this._applyBounceCounts( buf, budget, measuredLoopBound, n, lightKey );
|
|
940
1168
|
|
|
941
1169
|
this._readbackPending = false;
|
|
942
1170
|
|
|
@@ -960,7 +1188,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
960
1188
|
// Full-FRAME pixel count (CONVERGED_COUNT sums across all chunks) — not _wfMaxRayCount, which
|
|
961
1189
|
// after the chunk loop holds only the last band's pixel count.
|
|
962
1190
|
const total = this._wfRenderWidth.value * this._wfRenderHeight.value;
|
|
963
|
-
this.renderer.getArrayBufferAsync( cAttr ).then( ( buf ) => {
|
|
1191
|
+
this.renderer.getArrayBufferAsync( cAttr, null, 0, COUNTER.COUNT * 4 ).then( ( buf ) => {
|
|
964
1192
|
|
|
965
1193
|
if ( cgen === this._readbackGeneration && total > 0 ) this._applyCounters( buf, total );
|
|
966
1194
|
|
|
@@ -993,17 +1221,18 @@ export class PathTracer extends PathTracerStage {
|
|
|
993
1221
|
const loopBound = this._bounceLoopBound();
|
|
994
1222
|
const n = this._queueManager.MAX_BOUNCE_SNAPSHOTS;
|
|
995
1223
|
const total = this._wfRenderWidth.value * this._wfRenderHeight.value;
|
|
1224
|
+
const lightKey = this._integrator?.curveKey ?? null;
|
|
996
1225
|
|
|
997
1226
|
const entry = { due: this.frameCount + this._readbackEveryNFrames, read: null, apply: null };
|
|
998
1227
|
entry.read = Promise.all( [
|
|
999
1228
|
this.renderer.getArrayBufferAsync( bounceAttr ),
|
|
1000
|
-
this.renderer.getArrayBufferAsync( counterAttr ),
|
|
1229
|
+
this.renderer.getArrayBufferAsync( counterAttr, null, 0, COUNTER.COUNT * 4 ),
|
|
1001
1230
|
] ).then( ( [ bounceBuf, counterBuf ] ) => {
|
|
1002
1231
|
|
|
1003
1232
|
entry.apply = () => {
|
|
1004
1233
|
|
|
1005
1234
|
if ( gen !== this._readbackGeneration ) return;
|
|
1006
|
-
this._applyBounceCounts( bounceBuf, budget, loopBound, n );
|
|
1235
|
+
this._applyBounceCounts( bounceBuf, budget, loopBound, n, lightKey );
|
|
1007
1236
|
if ( total > 0 ) this._applyCounters( counterBuf, total );
|
|
1008
1237
|
|
|
1009
1238
|
};
|
|
@@ -1019,11 +1248,13 @@ export class PathTracer extends PathTracerStage {
|
|
|
1019
1248
|
|
|
1020
1249
|
}
|
|
1021
1250
|
|
|
1022
|
-
_applyBounceCounts( buf, budget, loopBound, n ) {
|
|
1251
|
+
_applyBounceCounts( buf, budget, loopBound, n, lightKey = null ) {
|
|
1023
1252
|
|
|
1024
1253
|
const all = new Uint32Array( buf.slice( 0 ) );
|
|
1025
1254
|
this._lastBounceCounts = all.subarray( 0, n );
|
|
1026
1255
|
this._lastBounceEnergy = all.subarray( n, 2 * n );
|
|
1256
|
+
// An integrator's light pass keeps its own curve after the camera's.
|
|
1257
|
+
this._integrator?.applyLightCurve( all.subarray( 2 * n, 3 * n ), all.subarray( 3 * n, 4 * n ), lightKey );
|
|
1027
1258
|
this._lastBounceCountsBudget = budget;
|
|
1028
1259
|
this._lastBounceCountsLoopBound = loopBound;
|
|
1029
1260
|
this._curveSizingValid = true;
|
|
@@ -1137,19 +1368,23 @@ export class PathTracer extends PathTracerStage {
|
|
|
1137
1368
|
// any resolution through this pool, so a small B just means more row-bands (works on weak / small-VRAM GPUs).
|
|
1138
1369
|
_computePathBudget() {
|
|
1139
1370
|
|
|
1140
|
-
if ( this._pathBudgetOverride > 0 ) return this._pathBudgetOverride;
|
|
1141
|
-
|
|
1142
1371
|
const RAY_BYTES = RAY_STRIDE * 16;
|
|
1143
|
-
const
|
|
1372
|
+
const HIT_BYTES = ( this._integrator?.hitStride ?? HIT_STRIDE ) * 16;
|
|
1373
|
+
const bytesPerPath = RAY_BYTES + HIT_BYTES + GBUFFER_STRIDE * 16
|
|
1144
1374
|
+ 4 + 4 /* activeIndices A/B */ + 4;
|
|
1145
1375
|
|
|
1146
1376
|
const limits = this.renderer?.backend?.device?.limits;
|
|
1147
1377
|
const maxBinding = limits?.maxStorageBufferBindingSize || ( 128 * 1024 * 1024 );
|
|
1148
1378
|
const maxBuffer = limits?.maxBufferSize || maxBinding;
|
|
1149
|
-
|
|
1150
|
-
const bByBinding = Math.floor( ( maxBinding * 0.9 ) / RAY_BYTES );
|
|
1151
1379
|
const deviceMemBytes = deviceMemoryGB( this.hostMemoryGB ).gb * 1024 * 1024 * 1024;
|
|
1152
|
-
|
|
1380
|
+
|
|
1381
|
+
// An integrator's light vertex cache shares the hit buffer's binding with the paths.
|
|
1382
|
+
const cacheBytes = this._integrator?.cacheBytes( maxBinding, deviceMemBytes ) ?? 0;
|
|
1383
|
+
|
|
1384
|
+
if ( this._pathBudgetOverride > 0 ) return this._pathBudgetOverride;
|
|
1385
|
+
|
|
1386
|
+
const bByBinding = Math.floor( Math.min( ( maxBinding * 0.9 ) / RAY_BYTES, ( maxBinding * 0.9 - cacheBytes ) / HIT_BYTES ) );
|
|
1387
|
+
const poolVramBudget = Math.min( deviceMemBytes * 0.25, maxBuffer * 4 ) - cacheBytes;
|
|
1153
1388
|
const bByVram = Math.floor( poolVramBudget / bytesPerPath );
|
|
1154
1389
|
|
|
1155
1390
|
const MIN_B = 512 * 512;
|
|
@@ -1208,6 +1443,20 @@ export class PathTracer extends PathTracerStage {
|
|
|
1208
1443
|
|
|
1209
1444
|
}
|
|
1210
1445
|
|
|
1446
|
+
/** The material layers the scene uses. */
|
|
1447
|
+
_layersToCompile() {
|
|
1448
|
+
|
|
1449
|
+
return this.materialData.materialLayers();
|
|
1450
|
+
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
/** Whether the kernels write the G-buffer: asked for directly, or for the hit distance that rides in it. */
|
|
1454
|
+
get _gBufferCompiled() {
|
|
1455
|
+
|
|
1456
|
+
return this._outputs.has( 'gBuffer' ) || this._outputs.has( 'hitDistance' );
|
|
1457
|
+
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1211
1460
|
_buildWavefrontKernels() {
|
|
1212
1461
|
|
|
1213
1462
|
const texNodes = this.shaderBuilder.getSceneTextureNodes();
|
|
@@ -1215,6 +1464,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1215
1464
|
|
|
1216
1465
|
// A fresh build binds the current lightStorageAttr — any pending realloc is covered.
|
|
1217
1466
|
this._lightBufferRealloc = false;
|
|
1467
|
+
this._outputsChanged = false;
|
|
1468
|
+
this._integrator?.beforeKernelBuild();
|
|
1218
1469
|
|
|
1219
1470
|
const w = this.storageTextures.renderWidth;
|
|
1220
1471
|
const h = this.storageTextures.renderHeight;
|
|
@@ -1231,13 +1482,14 @@ export class PathTracer extends PathTracerStage {
|
|
|
1231
1482
|
|
|
1232
1483
|
// Per-path buffers (RAY/HIT/rng) sized to the budget B and indexed by LOCAL slot r ∈ [0,B). _cap = B is
|
|
1233
1484
|
// baked into the SoA stride but never changes with resolution, so this build happens once (model load).
|
|
1485
|
+
const lightVertices = this._integrator?.lightVertices ?? 0;
|
|
1234
1486
|
if ( ! this._packedBuffers ) {
|
|
1235
1487
|
|
|
1236
|
-
this._packedBuffers = new PackedRayBuffer( B, this.renderer );
|
|
1488
|
+
this._packedBuffers = new PackedRayBuffer( B, this.renderer, lightVertices );
|
|
1237
1489
|
|
|
1238
1490
|
} else {
|
|
1239
1491
|
|
|
1240
|
-
this._packedBuffers.resize( B );
|
|
1492
|
+
this._packedBuffers.resize( B, lightVertices );
|
|
1241
1493
|
|
|
1242
1494
|
}
|
|
1243
1495
|
|
|
@@ -1275,6 +1527,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1275
1527
|
|
|
1276
1528
|
}
|
|
1277
1529
|
|
|
1530
|
+
this._integrator?.allocate( maxPixels );
|
|
1531
|
+
|
|
1278
1532
|
const m2RW = storage( this._m2Attr, 'float' );
|
|
1279
1533
|
const streakRW = storage( this._streakAttr, 'uint' );
|
|
1280
1534
|
const streakRO = storage( this._streakAttr, 'uint' ).toReadOnly();
|
|
@@ -1310,6 +1564,11 @@ export class PathTracer extends PathTracerStage {
|
|
|
1310
1564
|
const prevNormalDepth = this.shaderBuilder.prevNormalDepthTexNode;
|
|
1311
1565
|
const writeTex = this.storageTextures.getWriteTextures();
|
|
1312
1566
|
|
|
1567
|
+
const picked = this._pickedShadowRays();
|
|
1568
|
+
this._compiledPick = picked;
|
|
1569
|
+
const learnsVisibility = picked !== null;
|
|
1570
|
+
this._learnsVisibility = learnsVisibility;
|
|
1571
|
+
qm.setVisibilityTable( learnsVisibility );
|
|
1313
1572
|
const counters = qm.getCounters();
|
|
1314
1573
|
|
|
1315
1574
|
// Copy ACTIVE_RAY_COUNT into bounceCounts[currentBounce] for the readback survivor curve.
|
|
@@ -1393,6 +1652,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1393
1652
|
transmissiveBounces: this.transmissiveBounces,
|
|
1394
1653
|
transparentBackground: this.transparentBackground,
|
|
1395
1654
|
auxGBufferEnabled: this._auxGBufferUniform,
|
|
1655
|
+
gBuffer: this._gBufferCompiled,
|
|
1656
|
+
bidirectional: this._integrator?.uniforms ?? null,
|
|
1396
1657
|
};
|
|
1397
1658
|
const genFn = buildGenerateKernel( genParams );
|
|
1398
1659
|
this._kernelManager.register( 'generate',
|
|
@@ -1586,13 +1847,21 @@ export class PathTracer extends PathTracerStage {
|
|
|
1586
1847
|
const _mat = this.materialData;
|
|
1587
1848
|
const _env = this.environment;
|
|
1588
1849
|
// Consolidated size-bucket nodes (K sRGB + K linear). Empty buckets get placeholders so
|
|
1589
|
-
// every runtime branch references a valid node.
|
|
1590
|
-
// the Shade/Debug graphs are built so they bake in these (per-pipeline) nodes.
|
|
1850
|
+
// every runtime branch references a valid node.
|
|
1591
1851
|
const freshSrgbBuckets = buildBucketTextureNodes( _mat.srgbBuckets );
|
|
1592
1852
|
const freshLinearBuckets = buildBucketTextureNodes( _mat.linearBuckets );
|
|
1593
|
-
|
|
1594
|
-
// Alpha-cutout shadow rays sample albedo (sRGB pool)
|
|
1595
|
-
|
|
1853
|
+
// This renderer's resources, in the build context of each kernel that samples them (SceneResources.js).
|
|
1854
|
+
// Alpha-cutout shadow rays sample albedo (sRGB pool).
|
|
1855
|
+
const resources = {
|
|
1856
|
+
srgbBuckets: freshSrgbBuckets,
|
|
1857
|
+
linearBuckets: freshLinearBuckets,
|
|
1858
|
+
shadowAlbedoMaps: freshSrgbBuckets,
|
|
1859
|
+
goboMaps: texNodes.goboMapsTex,
|
|
1860
|
+
iesProfiles: texNodes.iesProfilesTex,
|
|
1861
|
+
alphaShadows: this.uniforms.get( 'enableAlphaShadows' ),
|
|
1862
|
+
materialLayers: this._compiledLayers = this._layersToCompile(),
|
|
1863
|
+
};
|
|
1864
|
+
const own = ( call ) => withSceneResources( call, resources );
|
|
1596
1865
|
const freshEnvTex = _env.environmentTexture ? texture( _env.environmentTexture ) : texNodes.envTex;
|
|
1597
1866
|
|
|
1598
1867
|
this._wfTexNodes = {
|
|
@@ -1603,8 +1872,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1603
1872
|
};
|
|
1604
1873
|
|
|
1605
1874
|
// Material-coherence sort gate (experiment): only worthwhile above a few materials.
|
|
1606
|
-
this._sortMaterials = (
|
|
1607
|
-
&& ( this.materialData?.materialCount ?? 0 ) > 8;
|
|
1875
|
+
this._sortMaterials = this.sortMaterials && ( this.materialData?.materialCount ?? 0 ) > 8;
|
|
1608
1876
|
|
|
1609
1877
|
const extFn = buildExtendKernel( {
|
|
1610
1878
|
bvhBuffer: freshBvh,
|
|
@@ -1669,7 +1937,6 @@ export class PathTracer extends PathTracerStage {
|
|
|
1669
1937
|
|
|
1670
1938
|
const shadeFn = buildShadeKernel( {
|
|
1671
1939
|
gBufferRW,
|
|
1672
|
-
envCompensationDelta: this.envCompensationDelta,
|
|
1673
1940
|
bvhBuffer: freshBvh,
|
|
1674
1941
|
triangleBuffer: freshTri,
|
|
1675
1942
|
materialBuffer: freshMat,
|
|
@@ -1721,7 +1988,6 @@ export class PathTracer extends PathTracerStage {
|
|
|
1721
1988
|
emissiveVec4Offset: this.emissiveVec4Offset,
|
|
1722
1989
|
emissiveTotalPower: this.emissiveTotalPower,
|
|
1723
1990
|
emissiveBoost: this.emissiveBoost,
|
|
1724
|
-
totalTriangleCount: this.totalTriangleCount,
|
|
1725
1991
|
enableEmissiveTriangleSampling: this.enableEmissiveTriangleSampling,
|
|
1726
1992
|
lightBVHNodeCount: this.lightBVHNodeCount,
|
|
1727
1993
|
reverseMapVec4Offset: this.reverseMapVec4Offset,
|
|
@@ -1729,17 +1995,29 @@ export class PathTracer extends PathTracerStage {
|
|
|
1729
1995
|
maxRayCount: this._wfMaxRayCount,
|
|
1730
1996
|
chunkRowBase: this._wfChunkRowBase,
|
|
1731
1997
|
auxGBufferEnabled: this._auxGBufferUniform,
|
|
1998
|
+
gBuffer: this._gBufferCompiled,
|
|
1732
1999
|
hasSun: this.hasSun,
|
|
1733
2000
|
sunDirection: this.sunDirection,
|
|
1734
2001
|
sunRadiance: this.sunRadiance,
|
|
1735
2002
|
sunParams: this.sunParams,
|
|
2003
|
+
bidirectional: this._integrator?.uniforms ?? null,
|
|
2004
|
+
hitDistanceEncode: this._outputs.get( 'hitDistance' )?.encode ?? null,
|
|
2005
|
+
materialLayers: this._compiledLayers,
|
|
2006
|
+
shadowRays: picked,
|
|
2007
|
+
cameraWorldMatrix: this.cameraWorldMatrix,
|
|
1736
2008
|
} );
|
|
1737
2009
|
this._kernelManager.register( 'shade',
|
|
1738
|
-
shadeFn().compute(
|
|
2010
|
+
own( shadeFn() ).compute(
|
|
1739
2011
|
[ Math.ceil( maxRays / SHADE_WG_SIZE ), 1, 1 ],
|
|
1740
2012
|
[ SHADE_WG_SIZE, 1, 1 ]
|
|
1741
2013
|
)
|
|
1742
2014
|
);
|
|
2015
|
+
if ( learnsVisibility ) {
|
|
2016
|
+
|
|
2017
|
+
this._kernelManager.register( 'visibilityClear', buildVisibilityClearKernel( { counters } ) );
|
|
2018
|
+
this._kernelManager.register( 'visibilityFold', buildVisibilityFoldKernel( { counters } ) );
|
|
2019
|
+
|
|
2020
|
+
}
|
|
1743
2021
|
|
|
1744
2022
|
// Subgroup prefix-sum variant when supported.
|
|
1745
2023
|
const subgroupsOK = this._useSubgroupCompact
|
|
@@ -1801,6 +2079,11 @@ export class PathTracer extends PathTracerStage {
|
|
|
1801
2079
|
copyFn().compute( [ Math.ceil( maxRays / LIST_WG_SIZE ), 1, 1 ], [ LIST_WG_SIZE, 1, 1 ] )
|
|
1802
2080
|
);
|
|
1803
2081
|
|
|
2082
|
+
this._integrator?.registerKernels( {
|
|
2083
|
+
km: this._kernelManager, qm, pb, counters, bounceCountsBuf, wfCurrentBounce, copyReadB, copyWriteA, maxRays, w, own,
|
|
2084
|
+
freshLight, freshTri, freshBvh, freshMat, freshEnvTex, freshEnvCDF, materialLayers: this._compiledLayers,
|
|
2085
|
+
} );
|
|
2086
|
+
|
|
1804
2087
|
const fwFn = buildFinalWriteKernel( {
|
|
1805
2088
|
rayBufferRO: pb.rayBuffer.ro,
|
|
1806
2089
|
gBufferRO,
|
|
@@ -1823,6 +2106,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1823
2106
|
renderHeight: this._wfRenderHeight,
|
|
1824
2107
|
visMode: this.visMode,
|
|
1825
2108
|
auxGBufferEnabled: this._auxGBufferUniform,
|
|
2109
|
+
gBuffer: this._gBufferCompiled,
|
|
1826
2110
|
cleanAuxNormalEnabled: this._cleanAuxNormalUniform,
|
|
1827
2111
|
m2BufferRW: m2RW,
|
|
1828
2112
|
useAdaptiveSampling: this.useAdaptiveSampling,
|
|
@@ -1882,14 +2166,16 @@ export class PathTracer extends PathTracerStage {
|
|
|
1882
2166
|
debugVisScale: this.debugVisScale,
|
|
1883
2167
|
frame: this.frame,
|
|
1884
2168
|
} );
|
|
2169
|
+
// Only the debug views dispatch it, so it compiles when one is first chosen.
|
|
1885
2170
|
this._kernelManager.register( 'debug',
|
|
1886
|
-
debugFn().compute(
|
|
2171
|
+
own( debugFn() ).compute(
|
|
1887
2172
|
[ Math.ceil( w / DEBUG_WG_SIZE ), Math.ceil( h / DEBUG_WG_SIZE ), 1 ],
|
|
1888
2173
|
[ DEBUG_WG_SIZE, DEBUG_WG_SIZE, 1 ]
|
|
1889
|
-
)
|
|
2174
|
+
),
|
|
2175
|
+
{ eager: false },
|
|
1890
2176
|
);
|
|
1891
2177
|
|
|
1892
|
-
this.
|
|
2178
|
+
this._compileKernels();
|
|
1893
2179
|
|
|
1894
2180
|
const bufferBytes = ( this._packedBuffers?.totalBytes ?? 0 ) + ( this._queueManager?.totalBytes ?? 0 );
|
|
1895
2181
|
|
|
@@ -1898,6 +2184,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1898
2184
|
`${fmt.mb( bufferBytes )} wavefront buffers`,
|
|
1899
2185
|
`budget ${fmt.n( B )} paths`,
|
|
1900
2186
|
this._numChunks > 1 ? `${this._numChunks} chunks of ≤${this._chunkRows} rows` : null,
|
|
2187
|
+
this._integrator?.describe() ?? null,
|
|
1901
2188
|
] ) );
|
|
1902
2189
|
|
|
1903
2190
|
}
|
|
@@ -1930,6 +2217,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1930
2217
|
const km = this._kernelManager;
|
|
1931
2218
|
km.setDispatchForGrid( 'generate', w, rows );
|
|
1932
2219
|
km.setDispatchForGrid( 'finalWrite', w, rows );
|
|
2220
|
+
km.setDispatchForGrid( 'splatResolve', w, rows );
|
|
1933
2221
|
km.setDispatchForCount( 'initActiveIndices', chunkPixels );
|
|
1934
2222
|
km.setDispatchForCount( 'buildActivePixels', chunkPixels );
|
|
1935
2223
|
|
|
@@ -1947,6 +2235,9 @@ export class PathTracer extends PathTracerStage {
|
|
|
1947
2235
|
this._m2Attr?.dispose?.();
|
|
1948
2236
|
this._streakAttr?.dispose?.();
|
|
1949
2237
|
this._frozenMaskAttr?.dispose?.();
|
|
2238
|
+
for ( const integrator of this._integratorInstances.values() ) integrator.dispose();
|
|
2239
|
+
this._integratorInstances.clear();
|
|
2240
|
+
this._integrator = null;
|
|
1950
2241
|
this._packedBuffers = null;
|
|
1951
2242
|
this._queueManager = null;
|
|
1952
2243
|
this._kernelManager = null;
|
|
@@ -1956,6 +2247,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1956
2247
|
this._frozenMaskAttr = null;
|
|
1957
2248
|
this._convDebugSource = null;
|
|
1958
2249
|
this._wavefrontReady = false;
|
|
2250
|
+
this._kernelGeneration ++;
|
|
2251
|
+
this._kernelsCompiling = null;
|
|
1959
2252
|
|
|
1960
2253
|
}
|
|
1961
2254
|
|