rayzee 7.11.0 → 7.12.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 +1 -1
- package/dist/rayzee.es.js +1866 -1657
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +18 -18
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/EngineDefaults.js +24 -1
- package/src/PathTracerApp.js +14 -0
- package/src/Pipeline/CompletionTracker.js +4 -1
- package/src/Processor/KernelManager.js +0 -1
- package/src/Processor/QueueManager.js +8 -1
- package/src/Processor/ShaderBuilder.js +3 -0
- package/src/RenderSettings.js +9 -0
- package/src/Stages/PathTracer.js +306 -34
- package/src/TSL/BVHTraversal.js +10 -3
- package/src/TSL/Debugger.js +1 -1
- package/src/TSL/FinalWriteKernel.js +110 -8
- package/src/TSL/GenerateKernel.js +74 -46
- package/src/TSL/ShadeKernel.js +80 -3
- package/src/managers/DenoisingManager.js +6 -0
- package/src/managers/UniformManager.js +15 -0
package/package.json
CHANGED
package/src/EngineDefaults.js
CHANGED
|
@@ -83,6 +83,19 @@ export const ENGINE_DEFAULTS = {
|
|
|
83
83
|
bounces: 3,
|
|
84
84
|
transmissiveBounces: 5,
|
|
85
85
|
maxSubsurfaceSteps: 8, // interactive default: low cap (bounded random-walk SSS)
|
|
86
|
+
|
|
87
|
+
// Adaptive sampling (Blender-style): stop the frame once enough pixels drop below the noise threshold.
|
|
88
|
+
useAdaptiveSampling: true,
|
|
89
|
+
noiseThreshold: 0.02, // per-pixel noise below which a pixel is converged
|
|
90
|
+
darkNoiseFloor: 0.003, // extra absolute-noise floor so dark pixels can converge too
|
|
91
|
+
adaptiveMinSamples: 8, // min samples before adaptive sampling can trigger
|
|
92
|
+
adaptiveStopFraction: 0.95, // retire the frame once this fraction of pixels has converged
|
|
93
|
+
// Per-pixel freeze: skip tracing pixels that individually converged (noise threshold only — no dark floor,
|
|
94
|
+
// which would bake dim regions too dark). Naturally engages only on static/idle views. See docs/specs/tier2-adaptive-sampling-plan.md.
|
|
95
|
+
usePixelFreeze: false,
|
|
96
|
+
pixelFreezeThreshold: 0.02, // per-pixel noise below which a pixel becomes a freeze candidate
|
|
97
|
+
pixelFreezeStability: 8, // consecutive candidate frames before a pixel freezes
|
|
98
|
+
|
|
86
99
|
samplingTechnique: 3,
|
|
87
100
|
enableEmissiveTriangleSampling: false,
|
|
88
101
|
emissiveBoost: 1.0,
|
|
@@ -556,10 +569,18 @@ export const DEFAULT_TEXTURE_MATRIX = [ 0, 0, 1, 1, 0, 0, 0, 1 ];
|
|
|
556
569
|
// 'interactive' — low-sample, bounded bounces, no offline denoising, controls enabled.
|
|
557
570
|
// 'production' — high-sample, deep bounces, OIDN enabled, controls disabled.
|
|
558
571
|
export const PRODUCTION_RENDER_CONFIG = {
|
|
559
|
-
maxSamples
|
|
572
|
+
// maxSamples is a CEILING: adaptive sampling retires the frame once adaptiveStopFraction of pixels converge,
|
|
573
|
+
// so easy scenes finish well under it while hard GI scenes use the full budget.
|
|
574
|
+
maxSamples: 150, bounces: 20, transmissiveBounces: 8, maxSubsurfaceSteps: 64,
|
|
560
575
|
renderMode: 1, enableAlphaShadows: true,
|
|
561
576
|
enableOIDN: true, oidnQuality: 'balance',
|
|
562
577
|
interactionModeEnabled: false,
|
|
578
|
+
// Looser thresholds + stop at 90%, leaning on OIDN to clean the residual tail.
|
|
579
|
+
useAdaptiveSampling: true,
|
|
580
|
+
noiseThreshold: 0.1,
|
|
581
|
+
darkNoiseFloor: 0.01,
|
|
582
|
+
adaptiveStopFraction: 0.9,
|
|
583
|
+
usePixelFreeze: true,
|
|
563
584
|
};
|
|
564
585
|
|
|
565
586
|
export const INTERACTIVE_RENDER_CONFIG = {
|
|
@@ -569,6 +590,8 @@ export const INTERACTIVE_RENDER_CONFIG = {
|
|
|
569
590
|
maxSubsurfaceSteps: ENGINE_DEFAULTS.maxSubsurfaceSteps,
|
|
570
591
|
enableOIDN: false, oidnQuality: 'fast',
|
|
571
592
|
interactionModeEnabled: true,
|
|
593
|
+
useAdaptiveSampling: true, // idle refine stops early when converged; frozen during motion
|
|
594
|
+
usePixelFreeze: true, // speeds up idle refinement on heavy/high-res views; inert while moving (freeze resets)
|
|
572
595
|
};
|
|
573
596
|
|
|
574
597
|
// Memory management constants
|
package/src/PathTracerApp.js
CHANGED
|
@@ -323,6 +323,7 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
323
323
|
const tracker = this.stages.pathTracer?.vramTracker;
|
|
324
324
|
const frame = this.stages.pathTracer?.frameCount ?? 0;
|
|
325
325
|
if ( tracker && ( frame <= 1 || frame % 30 === 0 ) ) tracker.measure();
|
|
326
|
+
|
|
326
327
|
updateStats( {
|
|
327
328
|
timeElapsed: this.completion.timeElapsed,
|
|
328
329
|
samples: getDisplaySamples( this.stages.pathTracer ),
|
|
@@ -1236,6 +1237,19 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
1236
1237
|
this.stages.pathTracer?.setUniform( 'renderMode', parseInt( config.renderMode ) );
|
|
1237
1238
|
this.stages.pathTracer?.setUniform( 'enableAlphaShadows', config.enableAlphaShadows ?? false );
|
|
1238
1239
|
|
|
1240
|
+
// Tier-1 convergence early-stop (live uniforms, no kernel rebuild). Threshold/min-samples fall back to
|
|
1241
|
+
// engine defaults when a config doesn't override them.
|
|
1242
|
+
this.stages.pathTracer?.setUniform( 'useAdaptiveSampling', config.useAdaptiveSampling ?? false );
|
|
1243
|
+
this.stages.pathTracer?.setUniform( 'noiseThreshold', config.noiseThreshold ?? DEFAULT_STATE.noiseThreshold );
|
|
1244
|
+
this.stages.pathTracer?.setUniform( 'darkNoiseFloor', config.darkNoiseFloor ?? DEFAULT_STATE.darkNoiseFloor );
|
|
1245
|
+
this.stages.pathTracer?.setUniform( 'adaptiveStopFraction', config.adaptiveStopFraction ?? DEFAULT_STATE.adaptiveStopFraction );
|
|
1246
|
+
this.stages.pathTracer?.setUniform( 'adaptiveMinSamples', config.adaptiveMinSamples ?? DEFAULT_STATE.adaptiveMinSamples );
|
|
1247
|
+
|
|
1248
|
+
// Tier-2 per-pixel freeze (per-mode; falls back off when a config doesn't set it).
|
|
1249
|
+
this.stages.pathTracer?.setUniform( 'usePixelFreeze', config.usePixelFreeze ?? false );
|
|
1250
|
+
this.stages.pathTracer?.setUniform( 'pixelFreezeThreshold', config.pixelFreezeThreshold ?? DEFAULT_STATE.pixelFreezeThreshold );
|
|
1251
|
+
this.stages.pathTracer?.setUniform( 'pixelFreezeStability', config.pixelFreezeStability ?? DEFAULT_STATE.pixelFreezeStability );
|
|
1252
|
+
|
|
1239
1253
|
this.stages.pathTracer?.updateCompletionThreshold?.();
|
|
1240
1254
|
|
|
1241
1255
|
const denoiser = this.denoisingManager?.denoiser;
|
|
@@ -48,7 +48,10 @@ export class CompletionTracker {
|
|
|
48
48
|
|
|
49
49
|
if ( this.isTimeLimitReached( renderLimitMode, renderTimeLimit ) ) return true;
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
// Tier-1 convergence early-stop must agree with PathTracer.render()'s own check, else the app-level
|
|
52
|
+
// reconcile would flip isComplete back off and keep dispatching after the frame converged.
|
|
53
|
+
return pathTracer.frameCount >= pathTracer.completionThreshold
|
|
54
|
+
|| ( pathTracer._isConvergedComplete?.() ?? false );
|
|
52
55
|
|
|
53
56
|
}
|
|
54
57
|
|
|
@@ -16,7 +16,6 @@ const WORKGROUP_SIZES = {
|
|
|
16
16
|
connect: [ 256, 1, 1 ], // 1D shadow-ray-parallel
|
|
17
17
|
accumulate: [ 256, 1, 1 ], // 1D shadow-ray-parallel
|
|
18
18
|
compact: [ 256, 1, 1 ], // 1D ray-parallel
|
|
19
|
-
resetCounters: [ 1, 1, 1 ], // Single thread
|
|
20
19
|
finalWrite: [ 16, 16, 1 ], // 2D screen-space
|
|
21
20
|
};
|
|
22
21
|
|
|
@@ -11,7 +11,14 @@ export const COUNTER = {
|
|
|
11
11
|
ACTIVE_RAY_COUNT: 0,
|
|
12
12
|
// rays entering current bounce; snapshotted before ACTIVE_RAY_COUNT reset so over-sized dispatch is safe.
|
|
13
13
|
ENTERING_COUNT: 1,
|
|
14
|
-
|
|
14
|
+
// per-frame count of pixels whose Tier-1 relative-error dropped below threshold; zeroed at frame start by
|
|
15
|
+
// initActiveIndices, incremented in FinalWrite, read back async to drive the whole-frame convergence early-stop.
|
|
16
|
+
CONVERGED_COUNT: 2,
|
|
17
|
+
// Tier-2 per-pixel freeze: FROZEN_COUNT = pixels skipped this frame; ACTIVE_PIXEL_COUNT = bounce-0 active
|
|
18
|
+
// count (maxRays − frozen), read back to size next frame's grid.
|
|
19
|
+
FROZEN_COUNT: 3,
|
|
20
|
+
ACTIVE_PIXEL_COUNT: 4,
|
|
21
|
+
COUNT: 5,
|
|
15
22
|
};
|
|
16
23
|
|
|
17
24
|
/** Ray flag bits packed into rayBounceFlags (uint) */
|
|
@@ -19,6 +19,7 @@ export class ShaderBuilder {
|
|
|
19
19
|
// Previous-frame texture nodes (sample from MRT RenderTarget)
|
|
20
20
|
this.prevColorTexNode = null;
|
|
21
21
|
this.prevAlbedoTexNode = null;
|
|
22
|
+
this.prevNormalDepthTexNode = null;
|
|
22
23
|
|
|
23
24
|
// Scene texture nodes cache (for in-place updates on model change)
|
|
24
25
|
this._sceneTextureNodes = null;
|
|
@@ -98,6 +99,7 @@ export class ShaderBuilder {
|
|
|
98
99
|
const readTextures = storageTextures.getReadTextures();
|
|
99
100
|
this.prevColorTexNode = texture( readTextures.color );
|
|
100
101
|
this.prevAlbedoTexNode = texture( readTextures.albedo );
|
|
102
|
+
this.prevNormalDepthTexNode = texture( readTextures.normalDepth );
|
|
101
103
|
|
|
102
104
|
const createArrayPlaceholder = () => {
|
|
103
105
|
|
|
@@ -137,6 +139,7 @@ export class ShaderBuilder {
|
|
|
137
139
|
|
|
138
140
|
this.prevColorTexNode = null;
|
|
139
141
|
this.prevAlbedoTexNode = null;
|
|
142
|
+
this.prevNormalDepthTexNode = null;
|
|
140
143
|
this._sceneTextureNodes = null;
|
|
141
144
|
|
|
142
145
|
}
|
package/src/RenderSettings.js
CHANGED
|
@@ -40,6 +40,15 @@ const SETTING_ROUTES = {
|
|
|
40
40
|
samplingTechnique: { uniform: 'samplingTechnique', reset: true },
|
|
41
41
|
fireflyThreshold: { uniform: 'fireflyThreshold', reset: true },
|
|
42
42
|
enableAlphaShadows: { uniform: 'enableAlphaShadows', reset: true },
|
|
43
|
+
// Adaptive sampling — whole-frame early-stop (useAdaptiveSampling) + per-pixel freeze (usePixelFreeze)
|
|
44
|
+
useAdaptiveSampling: { uniform: 'useAdaptiveSampling', reset: true },
|
|
45
|
+
noiseThreshold: { uniform: 'noiseThreshold', reset: true },
|
|
46
|
+
darkNoiseFloor: { uniform: 'darkNoiseFloor', reset: true },
|
|
47
|
+
adaptiveMinSamples: { uniform: 'adaptiveMinSamples', reset: true },
|
|
48
|
+
adaptiveStopFraction: { uniform: 'adaptiveStopFraction', reset: true },
|
|
49
|
+
usePixelFreeze: { uniform: 'usePixelFreeze', reset: true },
|
|
50
|
+
pixelFreezeThreshold: { uniform: 'pixelFreezeThreshold', reset: true },
|
|
51
|
+
pixelFreezeStability: { uniform: 'pixelFreezeStability', reset: true },
|
|
43
52
|
enableEmissiveTriangleSampling: { uniform: 'enableEmissiveTriangleSampling', reset: true },
|
|
44
53
|
emissiveBoost: { uniform: 'emissiveBoost', reset: true },
|
|
45
54
|
visMode: { uniform: 'visMode', reset: true },
|