rayzee 10.0.0 → 11.0.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-BRQvLggb.js +4300 -0
- package/dist/AssetConfig-DSEntE65.js +30 -0
- package/dist/BidirectionalIntegrator-9lZQxFVH.js +934 -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-BCXylThH.js} +8 -6
- package/dist/{NeuralSuperRes-PkgDLQcD.js → NeuralSuperRes-sZAeS142.js} +55 -120
- package/dist/PathTracer-CQPW06Mm.js +29971 -0
- package/dist/PhysicalSky-BvqCw_dy.js +1219 -0
- package/dist/RayzeeRenderer-COpwotpU.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-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 +2551 -44024
- package/dist/rayzee.umd.js +528 -487
- package/dist/sceneCachePolicy-BSSsKY98.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 +1 -1
- package/src/Processor/ArchiveImporter.js +1259 -0
- 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 +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 +39 -5
- package/src/Processor/ReinsertionOptimizer.js +2 -2
- 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 +3899 -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 +338 -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 +204 -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 +147 -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 +165 -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 +218 -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 +964 -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 +833 -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,22 @@ export class PathTracer extends PathTracerStage {
|
|
|
1208
1443
|
|
|
1209
1444
|
}
|
|
1210
1445
|
|
|
1446
|
+
/** The material layers the scene uses; bidirectional leaves diffuse transmission out (its paths do not cross surfaces). */
|
|
1447
|
+
_layersToCompile() {
|
|
1448
|
+
|
|
1449
|
+
const layers = this.materialData.materialLayers();
|
|
1450
|
+
if ( this._integrator ) layers.diffuseTransmission = false;
|
|
1451
|
+
return layers;
|
|
1452
|
+
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/** Whether the kernels write the G-buffer: asked for directly, or for the hit distance that rides in it. */
|
|
1456
|
+
get _gBufferCompiled() {
|
|
1457
|
+
|
|
1458
|
+
return this._outputs.has( 'gBuffer' ) || this._outputs.has( 'hitDistance' );
|
|
1459
|
+
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1211
1462
|
_buildWavefrontKernels() {
|
|
1212
1463
|
|
|
1213
1464
|
const texNodes = this.shaderBuilder.getSceneTextureNodes();
|
|
@@ -1215,6 +1466,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1215
1466
|
|
|
1216
1467
|
// A fresh build binds the current lightStorageAttr — any pending realloc is covered.
|
|
1217
1468
|
this._lightBufferRealloc = false;
|
|
1469
|
+
this._outputsChanged = false;
|
|
1470
|
+
this._integrator?.beforeKernelBuild();
|
|
1218
1471
|
|
|
1219
1472
|
const w = this.storageTextures.renderWidth;
|
|
1220
1473
|
const h = this.storageTextures.renderHeight;
|
|
@@ -1231,13 +1484,14 @@ export class PathTracer extends PathTracerStage {
|
|
|
1231
1484
|
|
|
1232
1485
|
// Per-path buffers (RAY/HIT/rng) sized to the budget B and indexed by LOCAL slot r ∈ [0,B). _cap = B is
|
|
1233
1486
|
// baked into the SoA stride but never changes with resolution, so this build happens once (model load).
|
|
1487
|
+
const lightVertices = this._integrator?.lightVertices ?? 0;
|
|
1234
1488
|
if ( ! this._packedBuffers ) {
|
|
1235
1489
|
|
|
1236
|
-
this._packedBuffers = new PackedRayBuffer( B, this.renderer );
|
|
1490
|
+
this._packedBuffers = new PackedRayBuffer( B, this.renderer, lightVertices );
|
|
1237
1491
|
|
|
1238
1492
|
} else {
|
|
1239
1493
|
|
|
1240
|
-
this._packedBuffers.resize( B );
|
|
1494
|
+
this._packedBuffers.resize( B, lightVertices );
|
|
1241
1495
|
|
|
1242
1496
|
}
|
|
1243
1497
|
|
|
@@ -1275,6 +1529,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1275
1529
|
|
|
1276
1530
|
}
|
|
1277
1531
|
|
|
1532
|
+
this._integrator?.allocate( maxPixels );
|
|
1533
|
+
|
|
1278
1534
|
const m2RW = storage( this._m2Attr, 'float' );
|
|
1279
1535
|
const streakRW = storage( this._streakAttr, 'uint' );
|
|
1280
1536
|
const streakRO = storage( this._streakAttr, 'uint' ).toReadOnly();
|
|
@@ -1310,6 +1566,11 @@ export class PathTracer extends PathTracerStage {
|
|
|
1310
1566
|
const prevNormalDepth = this.shaderBuilder.prevNormalDepthTexNode;
|
|
1311
1567
|
const writeTex = this.storageTextures.getWriteTextures();
|
|
1312
1568
|
|
|
1569
|
+
const picked = this._pickedShadowRays();
|
|
1570
|
+
this._compiledPick = picked;
|
|
1571
|
+
const learnsVisibility = picked !== null;
|
|
1572
|
+
this._learnsVisibility = learnsVisibility;
|
|
1573
|
+
qm.setVisibilityTable( learnsVisibility );
|
|
1313
1574
|
const counters = qm.getCounters();
|
|
1314
1575
|
|
|
1315
1576
|
// Copy ACTIVE_RAY_COUNT into bounceCounts[currentBounce] for the readback survivor curve.
|
|
@@ -1393,6 +1654,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1393
1654
|
transmissiveBounces: this.transmissiveBounces,
|
|
1394
1655
|
transparentBackground: this.transparentBackground,
|
|
1395
1656
|
auxGBufferEnabled: this._auxGBufferUniform,
|
|
1657
|
+
gBuffer: this._gBufferCompiled,
|
|
1658
|
+
bidirectional: this._integrator?.uniforms ?? null,
|
|
1396
1659
|
};
|
|
1397
1660
|
const genFn = buildGenerateKernel( genParams );
|
|
1398
1661
|
this._kernelManager.register( 'generate',
|
|
@@ -1586,13 +1849,21 @@ export class PathTracer extends PathTracerStage {
|
|
|
1586
1849
|
const _mat = this.materialData;
|
|
1587
1850
|
const _env = this.environment;
|
|
1588
1851
|
// 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.
|
|
1852
|
+
// every runtime branch references a valid node.
|
|
1591
1853
|
const freshSrgbBuckets = buildBucketTextureNodes( _mat.srgbBuckets );
|
|
1592
1854
|
const freshLinearBuckets = buildBucketTextureNodes( _mat.linearBuckets );
|
|
1593
|
-
|
|
1594
|
-
// Alpha-cutout shadow rays sample albedo (sRGB pool)
|
|
1595
|
-
|
|
1855
|
+
// This renderer's resources, in the build context of each kernel that samples them (SceneResources.js).
|
|
1856
|
+
// Alpha-cutout shadow rays sample albedo (sRGB pool).
|
|
1857
|
+
const resources = {
|
|
1858
|
+
srgbBuckets: freshSrgbBuckets,
|
|
1859
|
+
linearBuckets: freshLinearBuckets,
|
|
1860
|
+
shadowAlbedoMaps: freshSrgbBuckets,
|
|
1861
|
+
goboMaps: texNodes.goboMapsTex,
|
|
1862
|
+
iesProfiles: texNodes.iesProfilesTex,
|
|
1863
|
+
alphaShadows: this.uniforms.get( 'enableAlphaShadows' ),
|
|
1864
|
+
materialLayers: this._compiledLayers = this._layersToCompile(),
|
|
1865
|
+
};
|
|
1866
|
+
const own = ( call ) => withSceneResources( call, resources );
|
|
1596
1867
|
const freshEnvTex = _env.environmentTexture ? texture( _env.environmentTexture ) : texNodes.envTex;
|
|
1597
1868
|
|
|
1598
1869
|
this._wfTexNodes = {
|
|
@@ -1603,8 +1874,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1603
1874
|
};
|
|
1604
1875
|
|
|
1605
1876
|
// Material-coherence sort gate (experiment): only worthwhile above a few materials.
|
|
1606
|
-
this._sortMaterials = (
|
|
1607
|
-
&& ( this.materialData?.materialCount ?? 0 ) > 8;
|
|
1877
|
+
this._sortMaterials = this.sortMaterials && ( this.materialData?.materialCount ?? 0 ) > 8;
|
|
1608
1878
|
|
|
1609
1879
|
const extFn = buildExtendKernel( {
|
|
1610
1880
|
bvhBuffer: freshBvh,
|
|
@@ -1669,7 +1939,6 @@ export class PathTracer extends PathTracerStage {
|
|
|
1669
1939
|
|
|
1670
1940
|
const shadeFn = buildShadeKernel( {
|
|
1671
1941
|
gBufferRW,
|
|
1672
|
-
envCompensationDelta: this.envCompensationDelta,
|
|
1673
1942
|
bvhBuffer: freshBvh,
|
|
1674
1943
|
triangleBuffer: freshTri,
|
|
1675
1944
|
materialBuffer: freshMat,
|
|
@@ -1721,7 +1990,6 @@ export class PathTracer extends PathTracerStage {
|
|
|
1721
1990
|
emissiveVec4Offset: this.emissiveVec4Offset,
|
|
1722
1991
|
emissiveTotalPower: this.emissiveTotalPower,
|
|
1723
1992
|
emissiveBoost: this.emissiveBoost,
|
|
1724
|
-
totalTriangleCount: this.totalTriangleCount,
|
|
1725
1993
|
enableEmissiveTriangleSampling: this.enableEmissiveTriangleSampling,
|
|
1726
1994
|
lightBVHNodeCount: this.lightBVHNodeCount,
|
|
1727
1995
|
reverseMapVec4Offset: this.reverseMapVec4Offset,
|
|
@@ -1729,17 +1997,29 @@ export class PathTracer extends PathTracerStage {
|
|
|
1729
1997
|
maxRayCount: this._wfMaxRayCount,
|
|
1730
1998
|
chunkRowBase: this._wfChunkRowBase,
|
|
1731
1999
|
auxGBufferEnabled: this._auxGBufferUniform,
|
|
2000
|
+
gBuffer: this._gBufferCompiled,
|
|
1732
2001
|
hasSun: this.hasSun,
|
|
1733
2002
|
sunDirection: this.sunDirection,
|
|
1734
2003
|
sunRadiance: this.sunRadiance,
|
|
1735
2004
|
sunParams: this.sunParams,
|
|
2005
|
+
bidirectional: this._integrator?.uniforms ?? null,
|
|
2006
|
+
hitDistanceEncode: this._outputs.get( 'hitDistance' )?.encode ?? null,
|
|
2007
|
+
materialLayers: this._compiledLayers,
|
|
2008
|
+
shadowRays: picked,
|
|
2009
|
+
cameraWorldMatrix: this.cameraWorldMatrix,
|
|
1736
2010
|
} );
|
|
1737
2011
|
this._kernelManager.register( 'shade',
|
|
1738
|
-
shadeFn().compute(
|
|
2012
|
+
own( shadeFn() ).compute(
|
|
1739
2013
|
[ Math.ceil( maxRays / SHADE_WG_SIZE ), 1, 1 ],
|
|
1740
2014
|
[ SHADE_WG_SIZE, 1, 1 ]
|
|
1741
2015
|
)
|
|
1742
2016
|
);
|
|
2017
|
+
if ( learnsVisibility ) {
|
|
2018
|
+
|
|
2019
|
+
this._kernelManager.register( 'visibilityClear', buildVisibilityClearKernel( { counters } ) );
|
|
2020
|
+
this._kernelManager.register( 'visibilityFold', buildVisibilityFoldKernel( { counters } ) );
|
|
2021
|
+
|
|
2022
|
+
}
|
|
1743
2023
|
|
|
1744
2024
|
// Subgroup prefix-sum variant when supported.
|
|
1745
2025
|
const subgroupsOK = this._useSubgroupCompact
|
|
@@ -1801,6 +2081,11 @@ export class PathTracer extends PathTracerStage {
|
|
|
1801
2081
|
copyFn().compute( [ Math.ceil( maxRays / LIST_WG_SIZE ), 1, 1 ], [ LIST_WG_SIZE, 1, 1 ] )
|
|
1802
2082
|
);
|
|
1803
2083
|
|
|
2084
|
+
this._integrator?.registerKernels( {
|
|
2085
|
+
km: this._kernelManager, qm, pb, counters, bounceCountsBuf, wfCurrentBounce, copyReadB, copyWriteA, maxRays, w, own,
|
|
2086
|
+
freshLight, freshTri, freshBvh, freshMat, freshEnvTex, freshEnvCDF,
|
|
2087
|
+
} );
|
|
2088
|
+
|
|
1804
2089
|
const fwFn = buildFinalWriteKernel( {
|
|
1805
2090
|
rayBufferRO: pb.rayBuffer.ro,
|
|
1806
2091
|
gBufferRO,
|
|
@@ -1823,6 +2108,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1823
2108
|
renderHeight: this._wfRenderHeight,
|
|
1824
2109
|
visMode: this.visMode,
|
|
1825
2110
|
auxGBufferEnabled: this._auxGBufferUniform,
|
|
2111
|
+
gBuffer: this._gBufferCompiled,
|
|
1826
2112
|
cleanAuxNormalEnabled: this._cleanAuxNormalUniform,
|
|
1827
2113
|
m2BufferRW: m2RW,
|
|
1828
2114
|
useAdaptiveSampling: this.useAdaptiveSampling,
|
|
@@ -1882,14 +2168,16 @@ export class PathTracer extends PathTracerStage {
|
|
|
1882
2168
|
debugVisScale: this.debugVisScale,
|
|
1883
2169
|
frame: this.frame,
|
|
1884
2170
|
} );
|
|
2171
|
+
// Only the debug views dispatch it, so it compiles when one is first chosen.
|
|
1885
2172
|
this._kernelManager.register( 'debug',
|
|
1886
|
-
debugFn().compute(
|
|
2173
|
+
own( debugFn() ).compute(
|
|
1887
2174
|
[ Math.ceil( w / DEBUG_WG_SIZE ), Math.ceil( h / DEBUG_WG_SIZE ), 1 ],
|
|
1888
2175
|
[ DEBUG_WG_SIZE, DEBUG_WG_SIZE, 1 ]
|
|
1889
|
-
)
|
|
2176
|
+
),
|
|
2177
|
+
{ eager: false },
|
|
1890
2178
|
);
|
|
1891
2179
|
|
|
1892
|
-
this.
|
|
2180
|
+
this._compileKernels();
|
|
1893
2181
|
|
|
1894
2182
|
const bufferBytes = ( this._packedBuffers?.totalBytes ?? 0 ) + ( this._queueManager?.totalBytes ?? 0 );
|
|
1895
2183
|
|
|
@@ -1898,6 +2186,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1898
2186
|
`${fmt.mb( bufferBytes )} wavefront buffers`,
|
|
1899
2187
|
`budget ${fmt.n( B )} paths`,
|
|
1900
2188
|
this._numChunks > 1 ? `${this._numChunks} chunks of ≤${this._chunkRows} rows` : null,
|
|
2189
|
+
this._integrator?.describe() ?? null,
|
|
1901
2190
|
] ) );
|
|
1902
2191
|
|
|
1903
2192
|
}
|
|
@@ -1930,6 +2219,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
1930
2219
|
const km = this._kernelManager;
|
|
1931
2220
|
km.setDispatchForGrid( 'generate', w, rows );
|
|
1932
2221
|
km.setDispatchForGrid( 'finalWrite', w, rows );
|
|
2222
|
+
km.setDispatchForGrid( 'splatResolve', w, rows );
|
|
1933
2223
|
km.setDispatchForCount( 'initActiveIndices', chunkPixels );
|
|
1934
2224
|
km.setDispatchForCount( 'buildActivePixels', chunkPixels );
|
|
1935
2225
|
|
|
@@ -1947,6 +2237,9 @@ export class PathTracer extends PathTracerStage {
|
|
|
1947
2237
|
this._m2Attr?.dispose?.();
|
|
1948
2238
|
this._streakAttr?.dispose?.();
|
|
1949
2239
|
this._frozenMaskAttr?.dispose?.();
|
|
2240
|
+
for ( const integrator of this._integratorInstances.values() ) integrator.dispose();
|
|
2241
|
+
this._integratorInstances.clear();
|
|
2242
|
+
this._integrator = null;
|
|
1950
2243
|
this._packedBuffers = null;
|
|
1951
2244
|
this._queueManager = null;
|
|
1952
2245
|
this._kernelManager = null;
|
|
@@ -1956,6 +2249,8 @@ export class PathTracer extends PathTracerStage {
|
|
|
1956
2249
|
this._frozenMaskAttr = null;
|
|
1957
2250
|
this._convDebugSource = null;
|
|
1958
2251
|
this._wavefrontReady = false;
|
|
2252
|
+
this._kernelGeneration ++;
|
|
2253
|
+
this._kernelsCompiling = null;
|
|
1959
2254
|
|
|
1960
2255
|
}
|
|
1961
2256
|
|