rayzee 7.29.0 → 7.30.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/dist/rayzee.es.js +3558 -2971
- package/dist/rayzee.umd.js +56 -56
- package/package.json +1 -1
- package/src/EngineDefaults.js +75 -0
- package/src/PathTracerApp.js +10 -1
- package/src/Processor/PackedRayBuffer.js +26 -5
- package/src/Processor/StorageTexturePool.js +8 -4
- package/src/RenderSettings.js +4 -4
- package/src/Stages/Compositor.js +1 -0
- package/src/Stages/NRD.js +1395 -0
- package/src/Stages/NormalDepth.js +8 -4
- package/src/Stages/PathTracerStage.js +4 -0
- package/src/TSL/Common.js +8 -1
- package/src/TSL/FinalWriteKernel.js +9 -4
- package/src/TSL/GenerateKernel.js +1 -1
- package/src/TSL/ShadeKernel.js +14 -2
- package/src/index.js +5 -0
- package/src/managers/DenoisingManager.js +80 -21
package/package.json
CHANGED
package/src/EngineDefaults.js
CHANGED
|
@@ -224,6 +224,10 @@ export const ENGINE_DEFAULTS = {
|
|
|
224
224
|
asvgfQualityPreset: 'medium',
|
|
225
225
|
showAsvgfHeatmap: false,
|
|
226
226
|
|
|
227
|
+
// NRD (ReBLUR port) real-time denoiser — see NRD_DEFAULTS / NRD_QUALITY_PRESETS.
|
|
228
|
+
nrdQualityPreset: 'medium',
|
|
229
|
+
nrdDebugMode: 0,
|
|
230
|
+
|
|
227
231
|
// Auto-exposure settings
|
|
228
232
|
autoExposure: false,
|
|
229
233
|
autoExposureKeyValue: 0.18,
|
|
@@ -233,6 +237,16 @@ export const ENGINE_DEFAULTS = {
|
|
|
233
237
|
autoExposureAdaptSpeedDark: 0.5,
|
|
234
238
|
};
|
|
235
239
|
|
|
240
|
+
// Ray distance NormalDepth writes on a miss. Max finite half-float, so miss−miss diffs stay 0
|
|
241
|
+
// rather than Inf−Inf=NaN.
|
|
242
|
+
export const GBUFFER_MISS_DEPTH = 65504.0;
|
|
243
|
+
export const GBUFFER_MISS_THRESHOLD = 6e4;
|
|
244
|
+
|
|
245
|
+
// normHitDist = hitDist / (A + B·viewZ). A constant, not a uniform: the Shade write and the NRD
|
|
246
|
+
// decode must agree, and the normalization is a pure round trip.
|
|
247
|
+
export const NRD_HIT_DIST_A = 3.0;
|
|
248
|
+
export const NRD_HIT_DIST_B = 0.1;
|
|
249
|
+
|
|
236
250
|
// Albedo demodulation safety floor. ASVGF and BilateralFilter MUST use the
|
|
237
251
|
// same value — demod (`color / safeAlbedo`) and remod (`lighting * safeAlbedo`)
|
|
238
252
|
// only round-trip exactly when both sides agree.
|
|
@@ -307,6 +321,67 @@ export const ASVGF_QUALITY_PRESETS = {
|
|
|
307
321
|
}
|
|
308
322
|
};
|
|
309
323
|
|
|
324
|
+
// NRD ReBLUR port (Stages/NRD.js). Names follow nrd::ReblurSettings so NVIDIA's tuning notes apply.
|
|
325
|
+
export const NRD_DEFAULTS = {
|
|
326
|
+
maxAccumulatedFrameNum: 30,
|
|
327
|
+
maxFastAccumulatedFrameNum: 6,
|
|
328
|
+
maxStabilizedFrameNum: 63,
|
|
329
|
+
historyFixFrameNum: 3,
|
|
330
|
+
historyFixBasePixelStride: 14,
|
|
331
|
+
prepassBlurRadius: 30,
|
|
332
|
+
minBlurRadius: 1,
|
|
333
|
+
maxBlurRadius: 30,
|
|
334
|
+
lobeAngleFraction: 0.15,
|
|
335
|
+
roughnessFraction: 0.15,
|
|
336
|
+
planeDistanceSensitivity: 0.02,
|
|
337
|
+
minHitDistanceWeight: 0.1,
|
|
338
|
+
fastHistoryClampingSigmaScale: 2.0,
|
|
339
|
+
fireflySuppressorMinRelativeScale: 2.0,
|
|
340
|
+
enableAntiFirefly: true,
|
|
341
|
+
antilagLuminanceSigmaScale: 2.0,
|
|
342
|
+
antilagLuminanceSensitivity: 3.0,
|
|
343
|
+
disocclusionThreshold: 0.01,
|
|
344
|
+
convergenceS: 1.0,
|
|
345
|
+
convergenceB: 0.2,
|
|
346
|
+
convergenceP: 0.8,
|
|
347
|
+
// Share of the lobe the normal weight accepts before any history exists. NRD's own constant is
|
|
348
|
+
// 0.75, which its source flags as probably too much; at that width it smears curved surfaces.
|
|
349
|
+
lobeVolumePercent: 0.1,
|
|
350
|
+
// Progressive handover: input sample count at which the denoiser passes the render through untouched.
|
|
351
|
+
// 0 = 2 · maxAccumulatedFrameNum.
|
|
352
|
+
handoverFrames: 0,
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// Keys a preset may override. Applying one resets every key to its default first, so a preset only
|
|
356
|
+
// states its deltas and `medium` can be empty.
|
|
357
|
+
export const NRD_PRESET_KEYS = [
|
|
358
|
+
'maxAccumulatedFrameNum', 'maxFastAccumulatedFrameNum', 'maxStabilizedFrameNum',
|
|
359
|
+
'historyFixFrameNum', 'prepassBlurRadius', 'maxBlurRadius', 'enableAntiFirefly',
|
|
360
|
+
];
|
|
361
|
+
|
|
362
|
+
export const NRD_QUALITY_PRESETS = {
|
|
363
|
+
// Short history + no pre-pass: most responsive, noisiest.
|
|
364
|
+
low: {
|
|
365
|
+
maxAccumulatedFrameNum: 16,
|
|
366
|
+
maxFastAccumulatedFrameNum: 4,
|
|
367
|
+
maxStabilizedFrameNum: 16,
|
|
368
|
+
historyFixFrameNum: 2,
|
|
369
|
+
prepassBlurRadius: 0,
|
|
370
|
+
maxBlurRadius: 20,
|
|
371
|
+
enableAntiFirefly: false,
|
|
372
|
+
},
|
|
373
|
+
// nrd::ReblurSettings defaults.
|
|
374
|
+
medium: {},
|
|
375
|
+
// Longer history and wider kernels: smoother, more lag on lighting change.
|
|
376
|
+
high: {
|
|
377
|
+
maxAccumulatedFrameNum: 45,
|
|
378
|
+
maxFastAccumulatedFrameNum: 8,
|
|
379
|
+
historyFixFrameNum: 4,
|
|
380
|
+
prepassBlurRadius: 40,
|
|
381
|
+
maxBlurRadius: 40,
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
|
|
310
385
|
export const CAMERA_RANGES = {
|
|
311
386
|
fov: {
|
|
312
387
|
min: 10,
|
package/src/PathTracerApp.js
CHANGED
|
@@ -9,6 +9,7 @@ import { PathTracer } from './Stages/PathTracer.js';
|
|
|
9
9
|
import { NormalDepth } from './Stages/NormalDepth.js';
|
|
10
10
|
import { MotionVector } from './Stages/MotionVector.js';
|
|
11
11
|
import { ASVGF } from './Stages/ASVGF.js';
|
|
12
|
+
import { NRD } from './Stages/NRD.js';
|
|
12
13
|
import { Variance } from './Stages/Variance.js';
|
|
13
14
|
import { BilateralFilter } from './Stages/BilateralFilter.js';
|
|
14
15
|
import { EdgeFilter } from './Stages/EdgeFilter.js';
|
|
@@ -524,7 +525,12 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
524
525
|
if ( this.pipeline ) {
|
|
525
526
|
|
|
526
527
|
this.pipeline.reset();
|
|
527
|
-
if ( ! soft )
|
|
528
|
+
if ( ! soft ) {
|
|
529
|
+
|
|
530
|
+
this.pipeline.eventBus.emit( 'asvgf:reset' );
|
|
531
|
+
this.pipeline.eventBus.emit( 'denoiser:reset' );
|
|
532
|
+
|
|
533
|
+
}
|
|
528
534
|
|
|
529
535
|
}
|
|
530
536
|
|
|
@@ -2857,6 +2863,7 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
2857
2863
|
this.pipeline.addStage( this.stages.pathTracer );
|
|
2858
2864
|
this.pipeline.addStage( this.stages.normalDepth );
|
|
2859
2865
|
this.pipeline.addStage( this.stages.motionVector );
|
|
2866
|
+
this.pipeline.addStage( this.stages.nrd );
|
|
2860
2867
|
this.pipeline.addStage( this.stages.asvgf );
|
|
2861
2868
|
this.pipeline.addStage( this.stages.variance );
|
|
2862
2869
|
this.pipeline.addStage( this.stages.bilateralFilter );
|
|
@@ -3090,6 +3097,7 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
3090
3097
|
pathTracer: this.stages.pathTracer
|
|
3091
3098
|
} );
|
|
3092
3099
|
this.stages.asvgf = new ASVGF( this.renderer, { enabled: false } );
|
|
3100
|
+
this.stages.nrd = new NRD( this.renderer, { enabled: false, pathTracer: this.stages.pathTracer } );
|
|
3093
3101
|
this.stages.variance = new Variance( this.renderer, { enabled: false } );
|
|
3094
3102
|
this.stages.bilateralFilter = new BilateralFilter( this.renderer, { enabled: false } );
|
|
3095
3103
|
this.stages.edgeFilter = new EdgeFilter( this.renderer, { enabled: false } );
|
|
@@ -3114,6 +3122,7 @@ export class PathTracerApp extends EventDispatcher {
|
|
|
3114
3122
|
normalDepth: this.stages.normalDepth,
|
|
3115
3123
|
motionVector: this.stages.motionVector,
|
|
3116
3124
|
asvgf: this.stages.asvgf,
|
|
3125
|
+
nrd: this.stages.nrd,
|
|
3117
3126
|
variance: this.stages.variance,
|
|
3118
3127
|
bilateralFilter: this.stages.bilateralFilter,
|
|
3119
3128
|
edgeFilter: this.stages.edgeFilter,
|
|
@@ -16,9 +16,10 @@ export const RAY_STRIDE = 7;
|
|
|
16
16
|
export const HIT_STRIDE = 2;
|
|
17
17
|
// Per-pixel G-buffer (first-hit MRT staging): 1 uvec4/pixel — half-packed normal/depth/albedo
|
|
18
18
|
// (pack2x16, no f32 bitcast); read by FinalWrite:
|
|
19
|
-
// .x=packSnorm2x16(normal.xy) .y=packSnorm2x16(normal.z, depth) .z=packUnorm2x16(albedo.rg)
|
|
19
|
+
// .x=packSnorm2x16(normal.xy) .y=packSnorm2x16(normal.z, depth) .z=packUnorm2x16(albedo.rg)
|
|
20
|
+
// .w=packUnorm2x16(albedo.b, normHitDist)
|
|
21
|
+
// normHitDist is written by Shade; writeGBuffer preserves it so the DDFA albedo commits can't zero it.
|
|
20
22
|
// Separate buffer from RAY (per-pixel, not per-ray×S) — written by Generate/Shade bounce-0.
|
|
21
|
-
// (A second lane reserved for an A-SVGF Tier-1 surface ID was removed — write-only, never read.)
|
|
22
23
|
export const GBUFFER_STRIDE = 1;
|
|
23
24
|
|
|
24
25
|
export const RAY = {
|
|
@@ -162,15 +163,35 @@ export const readRayRadiance = ( buf, id ) =>
|
|
|
162
163
|
// One uvec4 per pixel (stride 1); AoS base = pixelIndex * GBUFFER_STRIDE.
|
|
163
164
|
const gbLane = ( pixelIndex ) => uint( pixelIndex ).mul( GBUFFER_STRIDE );
|
|
164
165
|
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
// hitDist = null keeps the lane's current normHitDist.
|
|
167
|
+
export const writeGBuffer = ( buf, pixelIndex, normal, depth, albedo, hitDist = null ) => {
|
|
168
|
+
|
|
169
|
+
const lane = gbLane( pixelIndex );
|
|
170
|
+
const h = hitDist === null ? unpackUnorm2x16( buf.element( lane ).w ).y : float( hitDist );
|
|
171
|
+
return buf.element( lane ).assign( uvec4(
|
|
167
172
|
packSnorm2x16( vec2( normal.x, normal.y ) ),
|
|
168
173
|
packSnorm2x16( vec2( normal.z, depth ) ),
|
|
169
174
|
packUnorm2x16( vec2( albedo.x, albedo.y ) ),
|
|
170
|
-
packUnorm2x16( vec2( albedo.z,
|
|
175
|
+
packUnorm2x16( vec2( albedo.z, h ) ),
|
|
176
|
+
) );
|
|
177
|
+
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export const writeGBufferHitDist = ( buf, pixelIndex, normHitDist ) => {
|
|
181
|
+
|
|
182
|
+
const lane = gbLane( pixelIndex );
|
|
183
|
+
const cur = buf.element( lane ).toVar();
|
|
184
|
+
return buf.element( lane ).assign( uvec4(
|
|
185
|
+
cur.x, cur.y, cur.z,
|
|
186
|
+
packUnorm2x16( vec2( unpackUnorm2x16( cur.w ).x, normHitDist ) ),
|
|
171
187
|
) );
|
|
188
|
+
|
|
189
|
+
};
|
|
190
|
+
|
|
172
191
|
export const readGBuffer = ( buf, pixelIndex ) => buf.element( gbLane( pixelIndex ) );
|
|
173
192
|
|
|
193
|
+
export const gbDecodeHitDist = ( packed ) => unpackUnorm2x16( packed.w ).y;
|
|
194
|
+
|
|
174
195
|
// Decode for FinalWrite. normalDepth.xyz matches the prior path (normal*0.5+0.5), .w = raw depth.
|
|
175
196
|
export const gbDecodeNormalDepth = ( packed ) => {
|
|
176
197
|
|
|
@@ -19,17 +19,21 @@ import { createLogger, fmt } from '../utils/Logger.js';
|
|
|
19
19
|
|
|
20
20
|
const log = createLogger( 'gpu' );
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// Compute-output StorageTexture at the reserved size, never resized (see above). LinearFilter is
|
|
23
|
+
// load-bearing: textureLoad codegen requires it on a StorageTexture.
|
|
24
|
+
export function createStorageTexture( type = FloatType, filter = LinearFilter ) {
|
|
23
25
|
|
|
24
26
|
const tex = new StorageTexture( MAX_STORAGE_TEXTURE_SIZE, MAX_STORAGE_TEXTURE_SIZE );
|
|
25
|
-
tex.type =
|
|
27
|
+
tex.type = type;
|
|
26
28
|
tex.format = RGBAFormat;
|
|
27
|
-
tex.minFilter =
|
|
28
|
-
tex.magFilter =
|
|
29
|
+
tex.minFilter = filter;
|
|
30
|
+
tex.magFilter = filter;
|
|
29
31
|
return tex;
|
|
30
32
|
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
const createWriteStorageTex = () => createStorageTexture();
|
|
36
|
+
|
|
33
37
|
export class StorageTexturePool {
|
|
34
38
|
|
|
35
39
|
constructor( width, height ) {
|
package/src/RenderSettings.js
CHANGED
|
@@ -182,10 +182,10 @@ export class RenderSettings extends EventDispatcher {
|
|
|
182
182
|
|
|
183
183
|
if ( ! isPanorama ) return;
|
|
184
184
|
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
if ( denoisingManager?.
|
|
185
|
+
// MotionVector unprojects through projectionMatrixInverse, which is meaningless once
|
|
186
|
+
// every pixel is its own direction. Fall back to the spatial-only denoiser rather
|
|
187
|
+
// than leaving no strategy.
|
|
188
|
+
if ( denoisingManager?.requiresMotionVectors ) denoisingManager.setDenoiserStrategy( 'edgeaware' );
|
|
189
189
|
// Auto-focus raycasts via Raycaster.setFromCamera, which only knows the frustum.
|
|
190
190
|
cameraManager?.setAutoFocusMode( 'manual' );
|
|
191
191
|
|
package/src/Stages/Compositor.js
CHANGED
|
@@ -70,6 +70,7 @@ export class Compositor extends RenderStage {
|
|
|
70
70
|
|| context.getTexture( 'edgeFiltering:output' )
|
|
71
71
|
|| context.getTexture( 'bilateralFiltering:output' )
|
|
72
72
|
|| context.getTexture( 'asvgf:output' )
|
|
73
|
+
|| context.getTexture( 'nrd:output' )
|
|
73
74
|
|| context.getTexture( 'pathtracer:color' );
|
|
74
75
|
|
|
75
76
|
}
|