rayzee 6.5.0 → 7.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 +24 -5
- package/dist/rayzee.es.js +7624 -7063
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +157 -236
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/EngineDefaults.js +26 -9
- package/src/PathTracerApp.js +118 -26
- package/src/Pipeline/PipelineContext.js +1 -2
- package/src/Pipeline/RenderPipeline.js +1 -1
- package/src/Pipeline/RenderStage.js +1 -1
- package/src/Processor/CameraOptimizer.js +0 -5
- package/src/Processor/GeometryExtractor.js +6 -0
- package/src/Processor/KernelManager.js +277 -0
- package/src/Processor/PackedRayBuffer.js +291 -0
- package/src/Processor/QueueManager.js +173 -0
- package/src/Processor/SceneProcessor.js +1 -0
- package/src/Processor/ShaderBuilder.js +11 -317
- package/src/Processor/StorageTexturePool.js +29 -15
- package/src/Processor/VRAMTracker.js +169 -0
- package/src/Processor/utils.js +11 -110
- package/src/RenderSettings.js +0 -3
- package/src/Stages/ASVGF.js +151 -78
- package/src/Stages/BilateralFilter.js +34 -10
- package/src/Stages/EdgeFilter.js +2 -3
- package/src/Stages/MotionVector.js +16 -9
- package/src/Stages/NormalDepth.js +17 -5
- package/src/Stages/PathTracer.js +671 -1456
- package/src/Stages/PathTracerStage.js +1451 -0
- package/src/Stages/SSRC.js +32 -15
- package/src/Stages/Variance.js +35 -12
- package/src/TSL/CompactKernel.js +110 -0
- package/src/TSL/DebugKernel.js +98 -0
- package/src/TSL/Environment.js +13 -11
- package/src/TSL/ExtendKernel.js +75 -0
- package/src/TSL/FinalWriteKernel.js +121 -0
- package/src/TSL/GenerateKernel.js +111 -0
- package/src/TSL/LightsSampling.js +2 -2
- package/src/TSL/PathTracerCore.js +43 -1039
- package/src/TSL/ShadeKernel.js +876 -0
- package/src/TSL/patches.js +81 -4
- package/src/index.js +3 -0
- package/src/managers/CameraManager.js +1 -1
- package/src/managers/DenoisingManager.js +40 -75
- package/src/managers/EnvironmentManager.js +30 -39
- package/src/managers/OverlayManager.js +7 -22
- package/src/managers/UniformManager.js +0 -3
- package/src/managers/helpers/TileHelper.js +2 -2
- package/src/Stages/AdaptiveSampling.js +0 -483
- package/src/TSL/PathTracer.js +0 -384
- package/src/managers/TileManager.js +0 -298
package/package.json
CHANGED
package/src/EngineDefaults.js
CHANGED
|
@@ -58,6 +58,10 @@ export const ENGINE_DEFAULTS = {
|
|
|
58
58
|
afScreenPoint: { x: 0.5, y: 0.5 },
|
|
59
59
|
afSmoothingFactor: 0.15,
|
|
60
60
|
|
|
61
|
+
// Multi-sample pool: S=samplesPerPixel rays/pixel/frame, FinalWrite averages them; interactive-only (renderMode 0, ≤ cap), else S=1.
|
|
62
|
+
// Pixel cap (768²) bounds pool memory; covers the 512² default, excludes ≥768².
|
|
63
|
+
wavefrontMultiSampleMaxPixels: 589824,
|
|
64
|
+
|
|
61
65
|
enablePathTracer: true,
|
|
62
66
|
enableAccumulation: true,
|
|
63
67
|
pauseRendering: false,
|
|
@@ -70,14 +74,9 @@ export const ENGINE_DEFAULTS = {
|
|
|
70
74
|
enableEmissiveTriangleSampling: false,
|
|
71
75
|
emissiveBoost: 1.0,
|
|
72
76
|
|
|
73
|
-
adaptiveSampling: false,
|
|
74
|
-
adaptiveSamplingMin: 1,
|
|
75
|
-
adaptiveSamplingMax: 8,
|
|
76
|
-
adaptiveSamplingVarianceThreshold: 0.1,
|
|
77
77
|
temporalVarianceWeight: 0.6,
|
|
78
78
|
enableEarlyTermination: true,
|
|
79
79
|
earlyTerminationThreshold: 0.002,
|
|
80
|
-
showAdaptiveSamplingHelper: false,
|
|
81
80
|
performanceModeAdaptive: 'medium',
|
|
82
81
|
|
|
83
82
|
fireflyThreshold: 3.0,
|
|
@@ -85,8 +84,7 @@ export const ENGINE_DEFAULTS = {
|
|
|
85
84
|
renderTimeLimit: 30,
|
|
86
85
|
renderMode: 0,
|
|
87
86
|
enableAlphaShadows: false,
|
|
88
|
-
|
|
89
|
-
tilesHelper: false,
|
|
87
|
+
tilesHelper: true, // show OIDN denoise / AI upscale tile progress overlay
|
|
90
88
|
showLightHelper: false,
|
|
91
89
|
|
|
92
90
|
directionalLightIntensity: 0,
|
|
@@ -129,6 +127,9 @@ export const ENGINE_DEFAULTS = {
|
|
|
129
127
|
asvgfPhiDepth: 1.0,
|
|
130
128
|
asvgfVarianceBoost: 1.0,
|
|
131
129
|
asvgfMaxAccumFrames: 32,
|
|
130
|
+
asvgfGradientStrength: 0.0,
|
|
131
|
+
asvgfGradientSigmaScale: 2.0,
|
|
132
|
+
asvgfGradientNoiseFloor: 0.0,
|
|
132
133
|
asvgfDebugMode: 0,
|
|
133
134
|
asvgfQualityPreset: 'medium',
|
|
134
135
|
showAsvgfHeatmap: false,
|
|
@@ -152,6 +153,12 @@ export const ENGINE_DEFAULTS = {
|
|
|
152
153
|
// only round-trip exactly when both sides agree.
|
|
153
154
|
export const ALBEDO_EPS = 0.01;
|
|
154
155
|
|
|
156
|
+
// Per-resolution compute StorageTextures are pre-allocated at this size and never
|
|
157
|
+
// resized (works around three.js r184 StorageTexture-resize bugs — see TSL/patches
|
|
158
|
+
// history). Render resolution must not exceed this on either axis; the engine warns
|
|
159
|
+
// and ignores larger requests.
|
|
160
|
+
export const MAX_STORAGE_TEXTURE_SIZE = 2048;
|
|
161
|
+
|
|
155
162
|
export const ASVGF_QUALITY_PRESETS = {
|
|
156
163
|
// phiColor / phiDepth are RELATIVE tolerances (fractions). Bigger = more
|
|
157
164
|
// permissive. gradientStrength = 0 keeps the adaptive-α boost off; the
|
|
@@ -191,6 +198,17 @@ export const ASVGF_QUALITY_PRESETS = {
|
|
|
191
198
|
}
|
|
192
199
|
};
|
|
193
200
|
|
|
201
|
+
// Adaptive variants — same SVGF quality as the base preset plus the temporal-
|
|
202
|
+
// gradient anti-lag enabled (gradientStrength > 0). The gradient measures real
|
|
203
|
+
// change in units of noise σ (gradientSigmaScale), so a static scene reads ~0
|
|
204
|
+
// and convergence is unaffected; only moving lights/anim/disocclusion drop
|
|
205
|
+
// history. Mutating the exported object is fine (const binding, mutable object);
|
|
206
|
+
// spreading lets each inherit its base. See ASVGF._buildGradientCompute.
|
|
207
|
+
const ADAPTIVE_GRADIENT = { gradientSigmaScale: 2.5, gradientNoiseFloor: 0.05 };
|
|
208
|
+
ASVGF_QUALITY_PRESETS.low_adaptive = { ...ASVGF_QUALITY_PRESETS.low, gradientStrength: 0.8, ...ADAPTIVE_GRADIENT };
|
|
209
|
+
ASVGF_QUALITY_PRESETS.medium_adaptive = { ...ASVGF_QUALITY_PRESETS.medium, gradientStrength: 1.0, ...ADAPTIVE_GRADIENT };
|
|
210
|
+
ASVGF_QUALITY_PRESETS.high_adaptive = { ...ASVGF_QUALITY_PRESETS.high, gradientStrength: 1.0, ...ADAPTIVE_GRADIENT };
|
|
211
|
+
|
|
194
212
|
export const CAMERA_RANGES = {
|
|
195
213
|
fov: {
|
|
196
214
|
min: 10,
|
|
@@ -467,7 +485,7 @@ export const DEFAULT_TEXTURE_MATRIX = [ 0, 0, 1, 1, 0, 0, 0, 1 ];
|
|
|
467
485
|
// 'production' — high-sample, deep bounces, OIDN enabled, controls disabled.
|
|
468
486
|
export const PRODUCTION_RENDER_CONFIG = {
|
|
469
487
|
maxSamples: 30, bounces: 20, transmissiveBounces: 8, maxSubsurfaceSteps: 64, samplesPerPixel: 1,
|
|
470
|
-
renderMode: 1, enableAlphaShadows: true,
|
|
488
|
+
renderMode: 1, enableAlphaShadows: true,
|
|
471
489
|
enableOIDN: true, oidnQuality: 'balance',
|
|
472
490
|
interactionModeEnabled: false,
|
|
473
491
|
};
|
|
@@ -477,7 +495,6 @@ export const INTERACTIVE_RENDER_CONFIG = {
|
|
|
477
495
|
samplesPerPixel: ENGINE_DEFAULTS.samplesPerPixel, renderMode: ENGINE_DEFAULTS.renderMode, enableAlphaShadows: ENGINE_DEFAULTS.enableAlphaShadows,
|
|
478
496
|
transmissiveBounces: ENGINE_DEFAULTS.transmissiveBounces,
|
|
479
497
|
maxSubsurfaceSteps: ENGINE_DEFAULTS.maxSubsurfaceSteps,
|
|
480
|
-
tiles: ENGINE_DEFAULTS.tiles, tilesHelper: ENGINE_DEFAULTS.tilesHelper,
|
|
481
498
|
enableOIDN: false, oidnQuality: 'fast',
|
|
482
499
|
interactionModeEnabled: true,
|
|
483
500
|
};
|
package/src/PathTracerApp.js
CHANGED
|
@@ -11,14 +11,13 @@ import { MotionVector } from './Stages/MotionVector.js';
|
|
|
11
11
|
import { ASVGF } from './Stages/ASVGF.js';
|
|
12
12
|
import { Variance } from './Stages/Variance.js';
|
|
13
13
|
import { BilateralFilter } from './Stages/BilateralFilter.js';
|
|
14
|
-
import { AdaptiveSampling } from './Stages/AdaptiveSampling.js';
|
|
15
14
|
import { EdgeFilter } from './Stages/EdgeFilter.js';
|
|
16
15
|
import { AutoExposure } from './Stages/AutoExposure.js';
|
|
17
16
|
import { SSRC } from './Stages/SSRC.js';
|
|
18
17
|
import { Compositor } from './Stages/Compositor.js';
|
|
19
18
|
import { RenderPipeline } from './Pipeline/RenderPipeline.js';
|
|
20
19
|
import { CompletionTracker } from './Pipeline/CompletionTracker.js';
|
|
21
|
-
import { ENGINE_DEFAULTS as DEFAULT_STATE, PRODUCTION_RENDER_CONFIG, INTERACTIVE_RENDER_CONFIG } from './EngineDefaults.js';
|
|
20
|
+
import { ENGINE_DEFAULTS as DEFAULT_STATE, PRODUCTION_RENDER_CONFIG, INTERACTIVE_RENDER_CONFIG, MAX_STORAGE_TEXTURE_SIZE } from './EngineDefaults.js';
|
|
22
21
|
import { updateStats, updateLoading, resetLoading, setStatusCallback, getDisplaySamples, disposeObjectFromMemory } from './Processor/utils.js';
|
|
23
22
|
import { BuildTimer } from './Processor/BuildTimer.js';
|
|
24
23
|
import { InteractionManager } from './managers/InteractionManager.js';
|
|
@@ -310,7 +309,14 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
310
309
|
|
|
311
310
|
}
|
|
312
311
|
|
|
313
|
-
|
|
312
|
+
this._ensureVRAMWiring();
|
|
313
|
+
const mem = this.stages.pathTracer?.vramTracker?.measure();
|
|
314
|
+
updateStats( {
|
|
315
|
+
timeElapsed: this.completion.timeElapsed,
|
|
316
|
+
samples: getDisplaySamples( this.stages.pathTracer ),
|
|
317
|
+
memoryUsed: mem?.current ?? 0,
|
|
318
|
+
memoryPeak: mem?.peak ?? 0,
|
|
319
|
+
} );
|
|
314
320
|
|
|
315
321
|
// Check time limit
|
|
316
322
|
if ( this.completion.isTimeLimitReached( this.settings.get( 'renderLimitMode' ), this.settings.get( 'renderTimeLimit' ) ) ) {
|
|
@@ -740,12 +746,9 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
740
746
|
this.stages.pathTracer.setupMaterial();
|
|
741
747
|
timer.end( 'Material setup (TSL compile)' );
|
|
742
748
|
|
|
743
|
-
// Front-load
|
|
744
|
-
//
|
|
745
|
-
// build time moves the stall to this loading moment.
|
|
746
|
-
// - raster fallback: compileAsync yields to main thread (r184+).
|
|
749
|
+
// Front-load raster pipeline creation (compileAsync yields to main thread, r184+) so the first
|
|
750
|
+
// animate frame is snappy. Wavefront compute kernels compile lazily on their first dispatch.
|
|
747
751
|
timer.start( 'Pipeline precompile' );
|
|
748
|
-
this.stages.pathTracer.shaderBuilder.forceCompile( this.renderer );
|
|
749
752
|
try {
|
|
750
753
|
|
|
751
754
|
await this.renderer.compileAsync( this.meshScene, this.cameraManager.camera );
|
|
@@ -845,11 +848,31 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
845
848
|
// Resize
|
|
846
849
|
// ═══════════════════════════════════════════════════════════════
|
|
847
850
|
|
|
851
|
+
/**
|
|
852
|
+
* Guard against render resolutions the compute pipeline can't support.
|
|
853
|
+
* Per-resolution StorageTextures are pre-allocated at MAX_STORAGE_TEXTURE_SIZE
|
|
854
|
+
* and never resized, so a larger request would overflow them. Warn and skip.
|
|
855
|
+
* @returns {boolean} true if the size is renderable
|
|
856
|
+
*/
|
|
857
|
+
_isRenderSizeSupported( width, height ) {
|
|
858
|
+
|
|
859
|
+
if ( width > MAX_STORAGE_TEXTURE_SIZE || height > MAX_STORAGE_TEXTURE_SIZE ) {
|
|
860
|
+
|
|
861
|
+
console.warn( `[Rayzee] Render resolution ${width}×${height} exceeds the ${MAX_STORAGE_TEXTURE_SIZE}px limit (compute storage textures are pre-allocated at ${MAX_STORAGE_TEXTURE_SIZE}px). Ignoring resize — use a resolution ≤ ${MAX_STORAGE_TEXTURE_SIZE}.` );
|
|
862
|
+
return false;
|
|
863
|
+
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
return true;
|
|
867
|
+
|
|
868
|
+
}
|
|
869
|
+
|
|
848
870
|
onResize() {
|
|
849
871
|
|
|
850
872
|
const width = this.canvas.clientWidth;
|
|
851
873
|
const height = this.canvas.clientHeight;
|
|
852
874
|
if ( width === 0 || height === 0 ) return;
|
|
875
|
+
if ( ! this._isRenderSizeSupported( width, height ) ) return;
|
|
853
876
|
|
|
854
877
|
this.renderer.setPixelRatio( 1.0 );
|
|
855
878
|
this.renderer.setSize( width, height, false );
|
|
@@ -878,6 +901,8 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
878
901
|
|
|
879
902
|
_applyRenderResize( renderWidth, renderHeight ) {
|
|
880
903
|
|
|
904
|
+
if ( ! this._isRenderSizeSupported( renderWidth, renderHeight ) ) return;
|
|
905
|
+
|
|
881
906
|
this.pipeline?.setSize( renderWidth, renderHeight );
|
|
882
907
|
this.denoisingManager?.setRenderSize( renderWidth, renderHeight );
|
|
883
908
|
this.needsReset = true;
|
|
@@ -889,6 +914,7 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
889
914
|
setCanvasSize( width, height ) {
|
|
890
915
|
|
|
891
916
|
if ( width === 0 || height === 0 ) return;
|
|
917
|
+
if ( ! this._isRenderSizeSupported( width, height ) ) return;
|
|
892
918
|
|
|
893
919
|
this.renderer.setPixelRatio( 1.0 );
|
|
894
920
|
this.renderer.setSize( width, height, false );
|
|
@@ -927,15 +953,6 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
927
953
|
|
|
928
954
|
this.stages.pathTracer?.setUniform( 'renderMode', parseInt( config.renderMode ) );
|
|
929
955
|
this.stages.pathTracer?.setUniform( 'enableAlphaShadows', config.enableAlphaShadows ?? false );
|
|
930
|
-
this.stages.pathTracer?.tileManager?.setTileCount( config.tiles );
|
|
931
|
-
|
|
932
|
-
const tileHelper = this.overlayManager?.getHelper( 'tiles' );
|
|
933
|
-
if ( tileHelper ) {
|
|
934
|
-
|
|
935
|
-
tileHelper.enabled = config.tilesHelper;
|
|
936
|
-
if ( ! config.tilesHelper ) tileHelper.hide();
|
|
937
|
-
|
|
938
|
-
}
|
|
939
956
|
|
|
940
957
|
this.stages.pathTracer?.updateCompletionThreshold?.();
|
|
941
958
|
|
|
@@ -958,6 +975,20 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
958
975
|
|
|
959
976
|
this.needsReset = false;
|
|
960
977
|
this.pauseRendering = false;
|
|
978
|
+
|
|
979
|
+
// Entering a final render starts a fresh peak window (Blender per-render semantics).
|
|
980
|
+
if ( isProduction ) {
|
|
981
|
+
|
|
982
|
+
const tracker = this.stages.pathTracer?.vramTracker;
|
|
983
|
+
if ( tracker ) {
|
|
984
|
+
|
|
985
|
+
tracker.measure();
|
|
986
|
+
tracker.resetPeak();
|
|
987
|
+
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
}
|
|
991
|
+
|
|
961
992
|
this.reset();
|
|
962
993
|
|
|
963
994
|
}
|
|
@@ -1067,6 +1098,69 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
1067
1098
|
|
|
1068
1099
|
}
|
|
1069
1100
|
|
|
1101
|
+
/** The path tracer's VRAM tracker, or null before stages are built. */
|
|
1102
|
+
get vram() {
|
|
1103
|
+
|
|
1104
|
+
return this.stages.pathTracer?.vramTracker ?? null;
|
|
1105
|
+
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* On-demand current/peak GPU memory snapshot.
|
|
1110
|
+
* @returns {{ current: number, peak: number, byCategory: Object }} bytes
|
|
1111
|
+
*/
|
|
1112
|
+
getMemoryInfo() {
|
|
1113
|
+
|
|
1114
|
+
return this.stages.pathTracer?.vramTracker?.measure() ?? { current: 0, peak: 0, byCategory: {} };
|
|
1115
|
+
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// Idempotent: registers the cross-stage texture provider and re-measures on
|
|
1119
|
+
// allocation events (scene/env load, resize) so peak is caught even while idle.
|
|
1120
|
+
_ensureVRAMWiring() {
|
|
1121
|
+
|
|
1122
|
+
if ( this._vramWired ) return;
|
|
1123
|
+
const tracker = this.stages.pathTracer?.vramTracker;
|
|
1124
|
+
if ( ! tracker ) return; // stages not ready yet
|
|
1125
|
+
|
|
1126
|
+
tracker.register( 'stages', () => this._collectStageTextures() );
|
|
1127
|
+
|
|
1128
|
+
const remeasure = () => tracker.measure();
|
|
1129
|
+
this._addTrackedListener( this, 'SceneRebuild', remeasure );
|
|
1130
|
+
this._addTrackedListener( this, 'EnvironmentLoaded', remeasure );
|
|
1131
|
+
this._addTrackedListener( this, 'resolution_changed', remeasure );
|
|
1132
|
+
|
|
1133
|
+
this._vramWired = true;
|
|
1134
|
+
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// Direct StorageTexture/RenderTarget properties of every non-pathTracer stage
|
|
1138
|
+
// (denoiser/G-buffer/filter targets). The pathTracer's own buffers/textures are
|
|
1139
|
+
// registered explicitly; measure() dedupes by identity so overlaps don't double-count.
|
|
1140
|
+
_collectStageTextures() {
|
|
1141
|
+
|
|
1142
|
+
const out = [];
|
|
1143
|
+
const stages = this.stages || {};
|
|
1144
|
+
const pt = stages.pathTracer;
|
|
1145
|
+
|
|
1146
|
+
for ( const key in stages ) {
|
|
1147
|
+
|
|
1148
|
+
const stage = stages[ key ];
|
|
1149
|
+
if ( ! stage || stage === pt || typeof stage !== 'object' ) continue;
|
|
1150
|
+
|
|
1151
|
+
for ( const prop in stage ) {
|
|
1152
|
+
|
|
1153
|
+
const v = stage[ prop ];
|
|
1154
|
+
if ( v && ( v.isTexture || v.isRenderTarget ) ) out.push( v );
|
|
1155
|
+
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
return out;
|
|
1161
|
+
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1070
1164
|
// ═══════════════════════════════════════════════════════════════
|
|
1071
1165
|
// Materials (absorbed from MaterialsAPI)
|
|
1072
1166
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -1207,6 +1301,7 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
1207
1301
|
maxBufferSize: adapterLimits.maxBufferSize,
|
|
1208
1302
|
maxStorageBufferBindingSize: adapterLimits.maxStorageBufferBindingSize,
|
|
1209
1303
|
maxColorAttachmentBytesPerSample: 128,
|
|
1304
|
+
maxStorageBuffersPerShaderStage: Math.min( adapterLimits.maxStorageBuffersPerShaderStage, 10 ),
|
|
1210
1305
|
}
|
|
1211
1306
|
} );
|
|
1212
1307
|
|
|
@@ -1265,7 +1360,6 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
1265
1360
|
this.pipeline.addStage( this.stages.asvgf );
|
|
1266
1361
|
this.pipeline.addStage( this.stages.variance );
|
|
1267
1362
|
this.pipeline.addStage( this.stages.bilateralFilter );
|
|
1268
|
-
this.pipeline.addStage( this.stages.adaptiveSampling );
|
|
1269
1363
|
this.pipeline.addStage( this.stages.edgeFilter );
|
|
1270
1364
|
this.pipeline.addStage( this.stages.autoExposure );
|
|
1271
1365
|
this.pipeline.addStage( this.stages.compositor );
|
|
@@ -1469,9 +1563,6 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
1469
1563
|
|
|
1470
1564
|
_createStages() {
|
|
1471
1565
|
|
|
1472
|
-
const adaptiveSamplingMax = this.settings.get( 'adaptiveSamplingMax' );
|
|
1473
|
-
const useAdaptiveSampling = this.settings.get( 'useAdaptiveSampling' );
|
|
1474
|
-
|
|
1475
1566
|
this.stages.pathTracer = new PathTracer( this.renderer, this.scene, this.cameraManager.camera );
|
|
1476
1567
|
this.stages.normalDepth = new NormalDepth( this.renderer, {
|
|
1477
1568
|
pathTracer: this.stages.pathTracer
|
|
@@ -1483,10 +1574,6 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
1483
1574
|
this.stages.asvgf = new ASVGF( this.renderer, { enabled: false } );
|
|
1484
1575
|
this.stages.variance = new Variance( this.renderer, { enabled: false } );
|
|
1485
1576
|
this.stages.bilateralFilter = new BilateralFilter( this.renderer, { enabled: false } );
|
|
1486
|
-
this.stages.adaptiveSampling = new AdaptiveSampling( this.renderer, {
|
|
1487
|
-
adaptiveSamplingMax,
|
|
1488
|
-
enabled: useAdaptiveSampling,
|
|
1489
|
-
} );
|
|
1490
1577
|
this.stages.edgeFilter = new EdgeFilter( this.renderer, { enabled: false } );
|
|
1491
1578
|
this.stages.autoExposure = new AutoExposure( this.renderer, { enabled: DEFAULT_STATE.autoExposure ?? false } );
|
|
1492
1579
|
|
|
@@ -1505,10 +1592,11 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
1505
1592
|
camera: this.cameraManager.camera,
|
|
1506
1593
|
stages: {
|
|
1507
1594
|
pathTracer: this.stages.pathTracer,
|
|
1595
|
+
normalDepth: this.stages.normalDepth,
|
|
1596
|
+
motionVector: this.stages.motionVector,
|
|
1508
1597
|
asvgf: this.stages.asvgf,
|
|
1509
1598
|
variance: this.stages.variance,
|
|
1510
1599
|
bilateralFilter: this.stages.bilateralFilter,
|
|
1511
|
-
adaptiveSampling: this.stages.adaptiveSampling,
|
|
1512
1600
|
edgeFilter: this.stages.edgeFilter,
|
|
1513
1601
|
ssrc: this.stages.ssrc,
|
|
1514
1602
|
autoExposure: this.stages.autoExposure,
|
|
@@ -1523,6 +1611,10 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
1523
1611
|
this.denoisingManager.setupDenoiser();
|
|
1524
1612
|
this.denoisingManager.setupUpscaler();
|
|
1525
1613
|
|
|
1614
|
+
// Seed G-buffer gating: NormalDepth/MotionVector start enabled (stage default)
|
|
1615
|
+
// but are only needed by real-time denoisers — idle them until one is active.
|
|
1616
|
+
this.denoisingManager._syncGBufferStages();
|
|
1617
|
+
|
|
1526
1618
|
// Set initial render resolution
|
|
1527
1619
|
const initW = this.canvas.clientWidth || 1;
|
|
1528
1620
|
const initH = this.canvas.clientHeight || 1;
|
|
@@ -42,7 +42,7 @@ export class PipelineContext {
|
|
|
42
42
|
accumulatedFrames: 0,
|
|
43
43
|
|
|
44
44
|
// Render modes
|
|
45
|
-
renderMode: 0, // 0 =
|
|
45
|
+
renderMode: 0, // 0 = interactive, 1 = production (full-frame in both)
|
|
46
46
|
interactionMode: false,
|
|
47
47
|
isComplete: false,
|
|
48
48
|
|
|
@@ -65,7 +65,6 @@ export class PipelineContext {
|
|
|
65
65
|
|
|
66
66
|
// Feature flags
|
|
67
67
|
enableASVGF: false,
|
|
68
|
-
enableAdaptiveSampling: false,
|
|
69
68
|
enableEdgeFiltering: false,
|
|
70
69
|
// Can be extended by stages as needed
|
|
71
70
|
};
|
|
@@ -22,7 +22,7 @@ import { EventDispatcher } from './EventDispatcher.js';
|
|
|
22
22
|
* // Add stages in execution order
|
|
23
23
|
* pipeline.addStage(new PathTracer(...));
|
|
24
24
|
* pipeline.addStage(new ASVGF(...));
|
|
25
|
-
* pipeline.addStage(new
|
|
25
|
+
* pipeline.addStage(new EdgeFilter(...));
|
|
26
26
|
*
|
|
27
27
|
* // Render all stages
|
|
28
28
|
* pipeline.render(writeBuffer);
|
|
@@ -28,7 +28,7 @@ export const StageExecutionMode = {
|
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* CONDITIONAL - Stage decides execution via shouldExecute() method
|
|
31
|
-
* Use for: Stages with complex execution logic
|
|
31
|
+
* Use for: Stages with complex execution logic
|
|
32
32
|
*/
|
|
33
33
|
CONDITIONAL: 'conditional'
|
|
34
34
|
};
|
|
@@ -25,7 +25,6 @@ export class CameraOptimizer {
|
|
|
25
25
|
this.interactionQualitySettings = {
|
|
26
26
|
maxBounceCount: 1,
|
|
27
27
|
numRaysPerPixel: 1,
|
|
28
|
-
useAdaptiveSampling: false,
|
|
29
28
|
useEnvMapIS: false,
|
|
30
29
|
// pixelRatio: 0.25,
|
|
31
30
|
enableAccumulation: false,
|
|
@@ -306,7 +305,6 @@ export class CameraOptimizer {
|
|
|
306
305
|
'ultra-low': {
|
|
307
306
|
maxBounceCount: 1,
|
|
308
307
|
numRaysPerPixel: 1,
|
|
309
|
-
useAdaptiveSampling: false,
|
|
310
308
|
useEnvMapIS: false,
|
|
311
309
|
pixelRatio: 0.125,
|
|
312
310
|
enableAccumulation: false
|
|
@@ -314,7 +312,6 @@ export class CameraOptimizer {
|
|
|
314
312
|
'low': {
|
|
315
313
|
maxBounceCount: 1,
|
|
316
314
|
numRaysPerPixel: 1,
|
|
317
|
-
useAdaptiveSampling: false,
|
|
318
315
|
useEnvMapIS: false,
|
|
319
316
|
pixelRatio: 0.25,
|
|
320
317
|
enableAccumulation: false
|
|
@@ -322,7 +319,6 @@ export class CameraOptimizer {
|
|
|
322
319
|
'medium': {
|
|
323
320
|
maxBounceCount: 2,
|
|
324
321
|
numRaysPerPixel: 1,
|
|
325
|
-
useAdaptiveSampling: false,
|
|
326
322
|
useEnvMapIS: true,
|
|
327
323
|
pixelRatio: 0.5,
|
|
328
324
|
enableAccumulation: false
|
|
@@ -330,7 +326,6 @@ export class CameraOptimizer {
|
|
|
330
326
|
'high': {
|
|
331
327
|
maxBounceCount: 3,
|
|
332
328
|
numRaysPerPixel: 1,
|
|
333
|
-
useAdaptiveSampling: true,
|
|
334
329
|
useEnvMapIS: true,
|
|
335
330
|
pixelRatio: 0.75,
|
|
336
331
|
enableAccumulation: true
|
|
@@ -536,6 +536,10 @@ export class GeometryExtractor {
|
|
|
536
536
|
// triangle extraction that stores directly in texture format
|
|
537
537
|
extractTrianglesInBatch( positions, normals, uvs, indices, triangleCount, materialIndex, meshIndex ) {
|
|
538
538
|
|
|
539
|
+
// Track per-material triangle count for sort-bin remap (item 41)
|
|
540
|
+
while ( this.materialTriangleCounts.length <= materialIndex ) this.materialTriangleCounts.push( 0 );
|
|
541
|
+
this.materialTriangleCounts[ materialIndex ] += triangleCount;
|
|
542
|
+
|
|
539
543
|
// Pre-allocate objects for positions, normals, and UVs
|
|
540
544
|
const posA = this._getVec3( 0 );
|
|
541
545
|
const posB = this._getVec3( 1 );
|
|
@@ -779,6 +783,7 @@ export class GeometryExtractor {
|
|
|
779
783
|
|
|
780
784
|
// Reset other arrays
|
|
781
785
|
this.materials = [];
|
|
786
|
+
this.materialTriangleCounts = []; // Per-material triangle count (for sort-bin remap, item 41)
|
|
782
787
|
this.meshes = [];
|
|
783
788
|
this.meshTriangleRanges = []; // Per-mesh { start, count } for TLAS/BLAS
|
|
784
789
|
this.maps = [];
|
|
@@ -816,6 +821,7 @@ export class GeometryExtractor {
|
|
|
816
821
|
triangleData: this.getTriangleData(), // Texture-ready Float32Array format
|
|
817
822
|
triangleCount: this.getTriangleCount(),
|
|
818
823
|
materials: this.materials,
|
|
824
|
+
materialTriangleCounts: this.materialTriangleCounts,
|
|
819
825
|
meshes: this.meshes,
|
|
820
826
|
meshTriangleRanges: this.meshTriangleRanges, // Per-mesh { start, count } for TLAS/BLAS
|
|
821
827
|
maps: this.maps,
|