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
|
@@ -10,7 +10,7 @@ import { RenderStage, StageExecutionMode } from '../Pipeline/RenderStage.js';
|
|
|
10
10
|
import { CameraOptimizer } from '../Processor/CameraOptimizer.js';
|
|
11
11
|
import { createPerformanceMonitor, calculateAccumulationAlpha, updateCompletionThreshold } from '../Processor/utils.js';
|
|
12
12
|
import { StorageTexturePool } from '../Processor/StorageTexturePool.js';
|
|
13
|
-
import { UniformManager } from '../managers/UniformManager.js';
|
|
13
|
+
import { UniformManager, LIGHT_FLOATS, lightListCapacity } from '../managers/UniformManager.js';
|
|
14
14
|
import { MaterialDataManager } from '../managers/MaterialDataManager.js';
|
|
15
15
|
import { EnvironmentManager } from '../managers/EnvironmentManager.js';
|
|
16
16
|
import { ShaderBuilder } from '../Processor/ShaderBuilder.js';
|
|
@@ -20,7 +20,8 @@ import { SceneProcessor } from '../Processor/SceneProcessor.js';
|
|
|
20
20
|
import { LightSerializer } from '../Processor/LightSerializer';
|
|
21
21
|
|
|
22
22
|
// Constants
|
|
23
|
-
import { ENGINE_DEFAULTS as DEFAULT_STATE
|
|
23
|
+
import { ENGINE_DEFAULTS as DEFAULT_STATE } from '../EngineDefaults.js';
|
|
24
|
+
import { TRIANGLE_DATA_LAYOUT } from '../Processor/BufferLayout.js';
|
|
24
25
|
import { TRI_GEO_ROWS, TRI_SHADE_ROWS } from '../TSL/Common.js';
|
|
25
26
|
import { createLogger, fmt } from '../utils/Logger.js';
|
|
26
27
|
|
|
@@ -53,8 +54,7 @@ const BVH_VEC4_PER_NODE = 4;
|
|
|
53
54
|
* Events emitted:
|
|
54
55
|
* - pathtracer:frameComplete - When a frame finishes rendering
|
|
55
56
|
* - camera:moved - When camera position/orientation changes
|
|
56
|
-
* -
|
|
57
|
-
* - asvgf:updateParameters - Update ASVGF parameters
|
|
57
|
+
* - pipeline:historyReset - temporal history from before is not comparable (render mode change)
|
|
58
58
|
*
|
|
59
59
|
* Textures published to context:
|
|
60
60
|
* - pathtracer:color - Main color output
|
|
@@ -113,6 +113,13 @@ export class PathTracerStage extends RenderStage {
|
|
|
113
113
|
// Initialize material data manager
|
|
114
114
|
this.materialData = new MaterialDataManager( this.sdfs );
|
|
115
115
|
this.materialData.callbacks.onReset = () => this.reset();
|
|
116
|
+
// A material edit can switch the diffuse transmission lobe on or off, which the shade kernel compiles in.
|
|
117
|
+
this.materialData.callbacks.onMaterialFeaturesChanged = () => {
|
|
118
|
+
|
|
119
|
+
this._materialFeaturesChanged = true;
|
|
120
|
+
|
|
121
|
+
};
|
|
122
|
+
|
|
116
123
|
// Material edits patch the per-triangle flags lane in the CPU records (`_triangleRecords`
|
|
117
124
|
// when chunked, `_triangleFlat` otherwise — not sdfs.triangleData, which the PathTracerApp
|
|
118
125
|
// build path never fills). The flags live in the shade rows, so only those go up again.
|
|
@@ -218,8 +225,8 @@ export class PathTracerStage extends RenderStage {
|
|
|
218
225
|
// Initialized with dummy data so TSL compilation never sees null.
|
|
219
226
|
this.lightStorageAttr = new StorageInstancedBufferAttribute( new Float32Array( 16 ), 4 );
|
|
220
227
|
this.lightStorageNode = storage( this.lightStorageAttr, 'vec4', 1 ).toReadOnly();
|
|
221
|
-
// Set when _rebuildLightBuffer had to grow-reallocate the attribute
|
|
222
|
-
// kernels still bind the old one and must be rebuilt to see the new data.
|
|
228
|
+
// Set when _rebuildLightBuffer had to grow-reallocate the attribute, or a light list grew
|
|
229
|
+
// (_writeLightList): compiled kernels still bind the old one and must be rebuilt to see the new data.
|
|
223
230
|
this._lightBufferRealloc = false;
|
|
224
231
|
|
|
225
232
|
// Cached CPU-side data — rebuilt into the packed buffer whenever any source changes.
|
|
@@ -375,16 +382,6 @@ export class PathTracerStage extends RenderStage {
|
|
|
375
382
|
|
|
376
383
|
} );
|
|
377
384
|
|
|
378
|
-
this.on( 'pathtracer:setCompletionThreshold', ( data ) => {
|
|
379
|
-
|
|
380
|
-
if ( data && data.threshold !== undefined ) {
|
|
381
|
-
|
|
382
|
-
this.completionThreshold = data.threshold;
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
} );
|
|
387
|
-
|
|
388
385
|
}
|
|
389
386
|
|
|
390
387
|
// ===== PUBLIC API METHODS =====
|
|
@@ -492,53 +489,36 @@ export class PathTracerStage extends RenderStage {
|
|
|
492
489
|
*/
|
|
493
490
|
_updateLightBufferNodes() {
|
|
494
491
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
this.numDirectionalLights.value = Math.floor( this.directionalLightsData.length / 12 );
|
|
500
|
-
|
|
501
|
-
} else {
|
|
502
|
-
|
|
503
|
-
this.numDirectionalLights.value = 0;
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// Area lights (16 floats per light — 13 base + normalize/spread/shape)
|
|
508
|
-
if ( this.areaLightsData && this.areaLightsData.length > 0 ) {
|
|
509
|
-
|
|
510
|
-
this.areaLightsBufferNode.array = Array.from( this.areaLightsData );
|
|
511
|
-
this.numAreaLights.value = Math.floor( this.areaLightsData.length / 16 );
|
|
512
|
-
|
|
513
|
-
} else {
|
|
514
|
-
|
|
515
|
-
this.numAreaLights.value = 0;
|
|
492
|
+
this._writeLightList( 'directional', this.directionalLightsData, this.numDirectionalLights );
|
|
493
|
+
this._writeLightList( 'area', this.areaLightsData, this.numAreaLights );
|
|
494
|
+
this._writeLightList( 'point', this.pointLightsData, this.numPointLights );
|
|
495
|
+
this._writeLightList( 'spot', this.spotLightsData, this.numSpotLights );
|
|
516
496
|
|
|
517
|
-
|
|
497
|
+
}
|
|
518
498
|
|
|
519
|
-
|
|
520
|
-
|
|
499
|
+
/**
|
|
500
|
+
* In place, because the shader bakes the list's length: sized per scene it compiled a program per
|
|
501
|
+
* light count, and three.js uploads only what fits the length it was built with, so a light added
|
|
502
|
+
* after a build was dropped. A list grows only past its capacity, and that rebuilds the kernels.
|
|
503
|
+
* @private
|
|
504
|
+
*/
|
|
505
|
+
_writeLightList( type, data, count ) {
|
|
521
506
|
|
|
522
|
-
|
|
523
|
-
|
|
507
|
+
const floats = LIGHT_FLOATS[ type ];
|
|
508
|
+
const node = this[ `${type}LightsBufferNode` ];
|
|
509
|
+
const lights = data ? Math.floor( data.length / floats ) : 0;
|
|
510
|
+
const used = lights * floats;
|
|
524
511
|
|
|
525
|
-
|
|
512
|
+
if ( used > node.array.length ) {
|
|
526
513
|
|
|
527
|
-
|
|
514
|
+
node.array = new Float32Array( lightListCapacity( type, lights ) * floats );
|
|
515
|
+
this._lightBufferRealloc = true;
|
|
528
516
|
|
|
529
517
|
}
|
|
530
518
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
this.spotLightsBufferNode.array = Array.from( this.spotLightsData );
|
|
535
|
-
this.numSpotLights.value = Math.floor( this.spotLightsData.length / 20 );
|
|
536
|
-
|
|
537
|
-
} else {
|
|
538
|
-
|
|
539
|
-
this.numSpotLights.value = 0;
|
|
540
|
-
|
|
541
|
-
}
|
|
519
|
+
if ( used > 0 ) node.array.set( data.subarray( 0, used ) );
|
|
520
|
+
node.array.fill( 0, used );
|
|
521
|
+
count.value = lights;
|
|
542
522
|
|
|
543
523
|
}
|
|
544
524
|
|
|
@@ -559,12 +539,13 @@ export class PathTracerStage extends RenderStage {
|
|
|
559
539
|
this.performanceMonitor?.reset();
|
|
560
540
|
|
|
561
541
|
// lastRenderMode is deliberately NOT invalidated here — clearing it made
|
|
562
|
-
//
|
|
542
|
+
// resetHistoryOnRenderModeChange see a phantom mode change 50 ms after every reset, wiping
|
|
563
543
|
// ASVGF's history. A real mode change is still caught by the renderMode comparison.
|
|
564
544
|
this.lastInteractionModeState = false;
|
|
565
545
|
|
|
566
546
|
// Only deterministic mode and lockstep readbacks rewind the seed axis; see _pinSeedToFrame.
|
|
567
547
|
if ( this._pinSeedToFrame || this._lockstep ) this._seedTick = 0;
|
|
548
|
+
this._accumulationLockstep = !! this._lockstep;
|
|
568
549
|
|
|
569
550
|
}
|
|
570
551
|
|
|
@@ -1088,26 +1069,48 @@ export class PathTracerStage extends RenderStage {
|
|
|
1088
1069
|
|
|
1089
1070
|
}
|
|
1090
1071
|
|
|
1091
|
-
/**
|
|
1092
|
-
|
|
1072
|
+
/**
|
|
1073
|
+
* Re-uploads triangles from the CPU records, adopting `triangleData` as them when given.
|
|
1074
|
+
* @param {Object} [triangleData]
|
|
1075
|
+
* @param {Array<{offset:number,count:number}>} [ranges] - only these, in record lanes; every triangle when omitted
|
|
1076
|
+
*/
|
|
1077
|
+
updateTriangleData( triangleData, ranges ) {
|
|
1093
1078
|
|
|
1094
1079
|
if ( triangleData?.chunks?.length > 1 ) this._triangleRecords = triangleData;
|
|
1095
1080
|
else if ( triangleData ) this._triangleFlat = triangleData.chunks ? triangleData.chunks[ 0 ] : triangleData;
|
|
1096
|
-
this.
|
|
1081
|
+
if ( ranges ) this.updateBufferRanges( ranges, [] );
|
|
1082
|
+
else this._uploadTriangles( 0, this._triangleRecordCount );
|
|
1097
1083
|
|
|
1098
1084
|
}
|
|
1099
1085
|
|
|
1100
|
-
/**
|
|
1101
|
-
|
|
1086
|
+
/**
|
|
1087
|
+
* Update BVH node data in the existing GPU buffer.
|
|
1088
|
+
* @param {Object} [bvhData]
|
|
1089
|
+
* @param {Array<{offset:number,count:number}>} [ranges] - only these, in floats; every node when omitted
|
|
1090
|
+
*/
|
|
1091
|
+
updateBVHData( bvhData, ranges ) {
|
|
1102
1092
|
|
|
1103
1093
|
if ( this._bvhRecords ) {
|
|
1104
1094
|
|
|
1105
|
-
|
|
1095
|
+
if ( bvhData?.chunks?.length > 1 ) this._bvhRecords = bvhData;
|
|
1096
|
+
if ( ranges ) this.updateBufferRanges( [], ranges );
|
|
1097
|
+
else uploadStorageChunks( this.renderer, this.bvhStorageAttr, this._bvhRecords.chunks );
|
|
1098
|
+
return;
|
|
1099
|
+
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
const flat = bvhData?.chunks ? bvhData.chunks[ 0 ] : bvhData;
|
|
1103
|
+
if ( ! ranges ) {
|
|
1104
|
+
|
|
1105
|
+
this._updateStorageBuffer( this.bvhStorageAttr, flat );
|
|
1106
1106
|
return;
|
|
1107
1107
|
|
|
1108
1108
|
}
|
|
1109
1109
|
|
|
1110
|
-
|
|
1110
|
+
// The attribute keeps its own array once the refit has moved the nodes into shared memory.
|
|
1111
|
+
const own = this.bvhStorageAttr?.array;
|
|
1112
|
+
if ( flat && own && flat !== own ) for ( const r of ranges ) own.set( flat.subarray( r.offset, r.offset + r.count ), r.offset );
|
|
1113
|
+
this.updateBufferRanges( [], ranges );
|
|
1111
1114
|
|
|
1112
1115
|
}
|
|
1113
1116
|
|
|
@@ -1266,6 +1269,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
1266
1269
|
|
|
1267
1270
|
this.createStorageTextures( width, height );
|
|
1268
1271
|
this.frameCount = 0;
|
|
1272
|
+
this._accumulationLockstep = false;
|
|
1269
1273
|
|
|
1270
1274
|
}
|
|
1271
1275
|
|
|
@@ -1413,7 +1417,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
1413
1417
|
|
|
1414
1418
|
// ===== ASVGF DENOISING MANAGEMENT =====
|
|
1415
1419
|
|
|
1416
|
-
|
|
1420
|
+
resetHistoryOnRenderModeChange( renderMode ) {
|
|
1417
1421
|
|
|
1418
1422
|
if ( renderMode !== this.lastRenderMode ) {
|
|
1419
1423
|
|
|
@@ -1433,8 +1437,7 @@ export class PathTracerStage extends RenderStage {
|
|
|
1433
1437
|
// History from the previous mode is not comparable. temporalAlpha is NOT
|
|
1434
1438
|
// touched here — it is owned by ASVGF_QUALITY_PRESETS, and overwriting it
|
|
1435
1439
|
// with a hardcoded value meant `medium` and `high` never took effect.
|
|
1436
|
-
this.emit( '
|
|
1437
|
-
this.emit( 'denoiser:reset' );
|
|
1440
|
+
this.emit( 'pipeline:historyReset' );
|
|
1438
1441
|
|
|
1439
1442
|
}
|
|
1440
1443
|
|
package/src/Stages/Variance.js
CHANGED
|
@@ -4,7 +4,7 @@ import { RenderTarget, TextureNode, StorageTexture } from 'three/webgpu';
|
|
|
4
4
|
import { FloatType, RGBAFormat, LinearFilter, Box2, Vector2 } from 'three';
|
|
5
5
|
import { RenderStage, StageExecutionMode } from '../Pipeline/RenderStage.js';
|
|
6
6
|
import { luminance } from '../TSL/Common.js';
|
|
7
|
-
import { MAX_STORAGE_TEXTURE_SIZE } from '../
|
|
7
|
+
import { MAX_STORAGE_TEXTURE_SIZE } from '../Processor/StorageTexturePool.js';
|
|
8
8
|
|
|
9
9
|
// NaN/±Inf guard: a poisoned luminance would otherwise corrupt the moment EMA forever
|
|
10
10
|
// (mean/meanSq → variance → BilateralFilter sigmaL). NaN (x!=x) → 0, ±Inf → [0,1e7].
|
package/src/Storage/BLASCache.js
CHANGED
package/src/Storage/CDFCache.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ENGINE_AREAS } from './
|
|
1
|
+
import { ENGINE_AREAS } from './areas.js';
|
|
2
2
|
import { sharedStorage } from './shared.js';
|
|
3
3
|
import { getAssetConfig } from '../AssetConfig.js';
|
|
4
4
|
|
|
5
|
-
const FORMAT =
|
|
5
|
+
const FORMAT = 5;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Where an environment texture came from, recorded by the loader so its sampling tables can be
|
|
@@ -25,7 +25,10 @@ function keyFor( texture ) {
|
|
|
25
25
|
|
|
26
26
|
const area = () => sharedStorage( getAssetConfig().cacheNamespace )?.area( ENGINE_AREAS.CDF ) ?? null;
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
const ARRAYS = [ 'exactConditional', 'exactMarginal', 'exactRowGuide', 'exactMarginalGuide' ];
|
|
29
|
+
const FILES = ARRAYS.map( name => `${name}.f32` );
|
|
30
|
+
|
|
31
|
+
/** @returns {Promise<?Object>} the fields of an EquirectHDRInfo build */
|
|
29
32
|
export async function loadCDF( texture ) {
|
|
30
33
|
|
|
31
34
|
const key = keyFor( texture );
|
|
@@ -34,14 +37,11 @@ export async function loadCDF( texture ) {
|
|
|
34
37
|
|
|
35
38
|
try {
|
|
36
39
|
|
|
37
|
-
const
|
|
38
|
-
if (
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
conditionalData: new Float32Array( await conditional.arrayBuffer() ),
|
|
43
|
-
totalSum, compensationDelta, width, height,
|
|
44
|
-
};
|
|
40
|
+
const files = await Promise.all( FILES.map( name => entry.file( name ) ) );
|
|
41
|
+
if ( files.some( f => ! f ) ) return null;
|
|
42
|
+
const arrays = await Promise.all( files.map( async f => new Float32Array( await f.arrayBuffer() ) ) );
|
|
43
|
+
const { totalSum, width, height, exactWidth, exactHeight, radianceIntegral } = entry.extra;
|
|
44
|
+
return { ...Object.fromEntries( ARRAYS.map( ( name, i ) => [ name, arrays[ i ] ] ) ), totalSum, width, height, exactWidth, exactHeight, radianceIntegral };
|
|
45
45
|
|
|
46
46
|
} finally {
|
|
47
47
|
|
|
@@ -51,20 +51,21 @@ export async function loadCDF( texture ) {
|
|
|
51
51
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export async function saveCDF( texture,
|
|
54
|
+
export async function saveCDF( texture, info ) {
|
|
55
55
|
|
|
56
|
+
const { totalSum, width, height, exactWidth, exactHeight, radianceIntegral } = info;
|
|
57
|
+
const arrays = ARRAYS.map( name => info[ name ] );
|
|
56
58
|
const key = keyFor( texture );
|
|
57
59
|
const target = key ? area() : null;
|
|
58
|
-
if ( ! target ||
|
|
60
|
+
if ( ! target || arrays.some( a => ! a ) ) return false;
|
|
59
61
|
|
|
60
|
-
const writer = await target.create( key, { label: texture.name || 'environment', expectedBytes:
|
|
62
|
+
const writer = await target.create( key, { label: texture.name || 'environment', expectedBytes: arrays.reduce( ( n, a ) => n + a.byteLength, 0 ) } );
|
|
61
63
|
if ( ! writer ) return false;
|
|
62
64
|
|
|
63
65
|
try {
|
|
64
66
|
|
|
65
|
-
await writer.write(
|
|
66
|
-
await writer.
|
|
67
|
-
await writer.commit( { totalSum, compensationDelta, width, height } );
|
|
67
|
+
for ( let i = 0; i < FILES.length; i ++ ) await writer.write( FILES[ i ], arrays[ i ] );
|
|
68
|
+
await writer.commit( { totalSum, width, height, exactWidth, exactHeight, radianceIntegral } );
|
|
68
69
|
return true;
|
|
69
70
|
|
|
70
71
|
} catch {
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
-
AnimationClip, BufferAttribute, BufferGeometry, DataTexture, Group, InstancedBufferAttribute, InstancedMesh,
|
|
13
|
-
MaterialLoader, Mesh, Object3D, OrthographicCamera, PerspectiveCamera,
|
|
12
|
+
AnimationClip, BufferAttribute, BufferGeometry, Color, DataTexture, Group, InstancedBufferAttribute, InstancedMesh,
|
|
13
|
+
MaterialLoader, Mesh, Object3D, OrthographicCamera, PerspectiveCamera, DirectionalLight, PointLight, SpotLight,
|
|
14
14
|
} from 'three';
|
|
15
15
|
|
|
16
16
|
export const SCENE_GRAPH_FORMAT = 2;
|
|
17
|
+
// Texture slots the engine reads off a material that three.js does not serialise.
|
|
18
|
+
const ENGINE_TEXTURES = [ 'diffuseTransmissionMap', 'diffuseTransmissionColorMap' ];
|
|
17
19
|
export const ARCHIVE_PATH = '__rayzeeArchivePath';
|
|
18
20
|
export const ARCHIVE_LOADER = '__rayzeeArchiveLoader';
|
|
19
21
|
|
|
@@ -28,6 +30,7 @@ const TEXTURE_PROPS = [
|
|
|
28
30
|
'flipY', 'generateMipmaps', 'premultiplyAlpha', 'unpackAlignment', 'colorSpace',
|
|
29
31
|
];
|
|
30
32
|
|
|
33
|
+
const LIGHT_PROPS = [ 'intensity', 'distance', 'decay', 'angle', 'penumbra' ];
|
|
31
34
|
const OBJECT_PROPS = [ 'name', 'visible', 'castShadow', 'receiveShadow', 'frustumCulled', 'renderOrder', 'matrixAutoUpdate' ];
|
|
32
35
|
|
|
33
36
|
export class SceneGraphUnsupported extends Error {
|
|
@@ -48,6 +51,9 @@ function kindOf( object ) {
|
|
|
48
51
|
if ( object.isMesh ) return 'Mesh';
|
|
49
52
|
if ( object.isPerspectiveCamera ) return 'PerspectiveCamera';
|
|
50
53
|
if ( object.isOrthographicCamera ) return 'OrthographicCamera';
|
|
54
|
+
if ( object.isDirectionalLight ) return 'DirectionalLight';
|
|
55
|
+
if ( object.isPointLight ) return 'PointLight';
|
|
56
|
+
if ( object.isSpotLight ) return 'SpotLight';
|
|
51
57
|
if ( object.isLight || object.isPoints || object.isLine || object.isSprite || object.isLOD ) return null;
|
|
52
58
|
if ( object.isGroup ) return 'Group';
|
|
53
59
|
return object.constructor === Object3D ? 'Object3D' : null;
|
|
@@ -163,6 +169,9 @@ function encodeMaterial( material, meta ) {
|
|
|
163
169
|
for ( const [ key, value ] of Object.entries( material ) ) if ( value?.isColor ) json.exactColors[ key ] = [ value.r, value.g, value.b ];
|
|
164
170
|
// MaterialLoader sets `reflectivity` after `ior`, and that setter rewrites ior with rounding.
|
|
165
171
|
if ( material.ior !== undefined ) json.exactIor = material.ior;
|
|
172
|
+
// Engine properties three.js does not know, so toJSON drops them.
|
|
173
|
+
if ( material.diffuseTransmission !== undefined ) json.diffuseTransmission = material.diffuseTransmission;
|
|
174
|
+
for ( const key of ENGINE_TEXTURES ) if ( material[ key ]?.isTexture ) ( json.engineTextures ??= {} )[ key ] = material[ key ].uuid;
|
|
166
175
|
return json;
|
|
167
176
|
|
|
168
177
|
}
|
|
@@ -234,6 +243,14 @@ export function encodeSceneGraph( root, { environment = null, animations = [], s
|
|
|
234
243
|
|
|
235
244
|
}
|
|
236
245
|
|
|
246
|
+
if ( object.isLight ) {
|
|
247
|
+
|
|
248
|
+
node.color = object.color.toArray();
|
|
249
|
+
for ( const prop of LIGHT_PROPS ) if ( object[ prop ] !== undefined ) node[ prop ] = object[ prop ];
|
|
250
|
+
if ( object.target ) node.target = object.target.uuid;
|
|
251
|
+
|
|
252
|
+
}
|
|
253
|
+
|
|
237
254
|
const index = nodes.push( node ) - 1;
|
|
238
255
|
for ( const child of object.children ) visit( child, index );
|
|
239
256
|
|
|
@@ -419,8 +436,16 @@ export async function decodeSceneGraph( manifest, data, { loadTexture } ) {
|
|
|
419
436
|
for ( const json of manifest.materials ) {
|
|
420
437
|
|
|
421
438
|
const material = materialLoader.parse( json );
|
|
422
|
-
for ( const [ key, rgb ] of Object.entries( json.exactColors ?? {} ) )
|
|
439
|
+
for ( const [ key, rgb ] of Object.entries( json.exactColors ?? {} ) ) {
|
|
440
|
+
|
|
441
|
+
if ( key === 'diffuseTransmissionColor' ) material[ key ] = new Color();
|
|
442
|
+
material[ key ]?.setRGB( rgb[ 0 ], rgb[ 1 ], rgb[ 2 ] );
|
|
443
|
+
|
|
444
|
+
}
|
|
445
|
+
|
|
423
446
|
if ( json.exactIor !== undefined ) material.ior = json.exactIor;
|
|
447
|
+
if ( json.diffuseTransmission !== undefined ) material.diffuseTransmission = json.diffuseTransmission;
|
|
448
|
+
for ( const [ key, uuid ] of Object.entries( json.engineTextures ?? {} ) ) if ( textures[ uuid ] ) material[ key ] = textures[ uuid ];
|
|
424
449
|
materials[ json.uuid ] = material;
|
|
425
450
|
|
|
426
451
|
}
|
|
@@ -462,6 +487,9 @@ export async function decodeSceneGraph( manifest, data, { loadTexture } ) {
|
|
|
462
487
|
case 'PerspectiveCamera': object = new PerspectiveCamera(); break;
|
|
463
488
|
case 'OrthographicCamera': object = new OrthographicCamera(); break;
|
|
464
489
|
case 'Group': object = new Group(); break;
|
|
490
|
+
case 'DirectionalLight': object = new DirectionalLight(); break;
|
|
491
|
+
case 'PointLight': object = new PointLight(); break;
|
|
492
|
+
case 'SpotLight': object = new SpotLight(); break;
|
|
465
493
|
default: object = new Object3D();
|
|
466
494
|
|
|
467
495
|
}
|
|
@@ -487,11 +515,26 @@ export async function decodeSceneGraph( manifest, data, { loadTexture } ) {
|
|
|
487
515
|
|
|
488
516
|
}
|
|
489
517
|
|
|
518
|
+
if ( object.isLight ) {
|
|
519
|
+
|
|
520
|
+
object.color.fromArray( node.color );
|
|
521
|
+
for ( const prop of LIGHT_PROPS ) if ( node[ prop ] !== undefined ) object[ prop ] = node[ prop ];
|
|
522
|
+
|
|
523
|
+
}
|
|
524
|
+
|
|
490
525
|
built.push( object );
|
|
491
526
|
if ( node.parent >= 0 ) built[ node.parent ].add( object );
|
|
492
527
|
|
|
493
528
|
}
|
|
494
529
|
|
|
530
|
+
// A light aims at its target, which is stored as an object of its own.
|
|
531
|
+
const byUuid = new Map( built.map( ( object ) => [ object.uuid, object ] ) );
|
|
532
|
+
manifest.nodes.forEach( ( node, i ) => {
|
|
533
|
+
|
|
534
|
+
if ( node.target && byUuid.has( node.target ) ) built[ i ].target = byUuid.get( node.target );
|
|
535
|
+
|
|
536
|
+
} );
|
|
537
|
+
|
|
495
538
|
return {
|
|
496
539
|
root: built[ 0 ],
|
|
497
540
|
environment: manifest.environment ? textures[ manifest.environment ] : null,
|
|
@@ -3,11 +3,9 @@ import { acquireLock, heldLockNames } from './locks.js';
|
|
|
3
3
|
import { entryIdFor } from './identity.js';
|
|
4
4
|
import { Emitter } from './events.js';
|
|
5
5
|
import { InlineTransport } from './inlineTransport.js';
|
|
6
|
+
import { STORAGE_KIND, ENGINE_AREAS } from './areas.js';
|
|
6
7
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
/** Areas the engine itself writes; hosts define their own with `defineArea`. */
|
|
10
|
-
export const ENGINE_AREAS = Object.freeze( { DOWNLOADS: 'downloads', ARCHIVES: 'archives', SCENES: 'scenes', CDF: 'cdf', SPILL: 'spill' } );
|
|
8
|
+
export { STORAGE_KIND, ENGINE_AREAS };
|
|
11
9
|
|
|
12
10
|
const META = 'meta.json';
|
|
13
11
|
const META_VERSION = 1;
|
|
@@ -17,6 +15,8 @@ const MAX_DEFAULT_BUDGET = 100 * 1024 ** 3;
|
|
|
17
15
|
const FREE_MARGIN = 64 * 1024 ** 2;
|
|
18
16
|
const STREAM_BATCH = 8 * 1024 ** 2;
|
|
19
17
|
const STREAM_WINDOW = 4;
|
|
18
|
+
// Other tabs write too, so the cache total kept in memory is listed again at most this often.
|
|
19
|
+
const CACHE_TOTAL_TTL_MS = 30_000;
|
|
20
20
|
|
|
21
21
|
const encoder = new TextEncoder();
|
|
22
22
|
|
|
@@ -152,6 +152,7 @@ export class EntryWriter {
|
|
|
152
152
|
this._sizes = { ...sizes };
|
|
153
153
|
this._append = append;
|
|
154
154
|
this._done = false;
|
|
155
|
+
this._committedBytes = append ? Object.values( sizes ).reduce( ( n, b ) => n + b, 0 ) : 0;
|
|
155
156
|
|
|
156
157
|
}
|
|
157
158
|
|
|
@@ -313,6 +314,7 @@ export class EntryWriter {
|
|
|
313
314
|
|
|
314
315
|
const { args, list } = transferable( JSON.stringify( meta ), { copy: false } );
|
|
315
316
|
await this._transport.call( 'writeFile', { path: this._path, name: META, ...args }, list );
|
|
317
|
+
if ( this.area.kind === STORAGE_KIND.CACHE ) this.area.manager._countCacheBytes( meta.bytes - this._committedBytes );
|
|
316
318
|
this.area.manager._changed( this.area.name );
|
|
317
319
|
return meta;
|
|
318
320
|
|
|
@@ -700,6 +702,7 @@ export class StorageManager extends Emitter {
|
|
|
700
702
|
this._transport = transport;
|
|
701
703
|
this._areas = new Map();
|
|
702
704
|
this._budget = null;
|
|
705
|
+
this._cacheTotal = null;
|
|
703
706
|
|
|
704
707
|
for ( const name of Object.values( ENGINE_AREAS ) ) this.defineArea( name, { kind: name === ENGINE_AREAS.SPILL ? STORAGE_KIND.SCRATCH : STORAGE_KIND.CACHE } );
|
|
705
708
|
|
|
@@ -775,6 +778,40 @@ export class StorageManager extends Emitter {
|
|
|
775
778
|
|
|
776
779
|
}
|
|
777
780
|
|
|
781
|
+
/**
|
|
782
|
+
* What cache areas hold together. Every new download asks, and a listing reads every entry's
|
|
783
|
+
* metadata, so it is listed once and kept current by this manager's own commits.
|
|
784
|
+
*/
|
|
785
|
+
async _cacheBytes() {
|
|
786
|
+
|
|
787
|
+
let total = this._cacheTotal;
|
|
788
|
+
if ( ! total || Date.now() - total.at > CACHE_TOTAL_TTL_MS ) {
|
|
789
|
+
|
|
790
|
+
total = this._cacheTotal = { at: Date.now(), bytes: 0, ready: null };
|
|
791
|
+
total.ready = this._cacheEntries().then( ( entries ) => {
|
|
792
|
+
|
|
793
|
+
total.bytes += entries.reduce( ( n, e ) => n + ( e.meta.bytes ?? 0 ), 0 );
|
|
794
|
+
|
|
795
|
+
} );
|
|
796
|
+
total.ready.catch( () => {
|
|
797
|
+
|
|
798
|
+
if ( this._cacheTotal === total ) this._cacheTotal = null;
|
|
799
|
+
|
|
800
|
+
} );
|
|
801
|
+
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
await total.ready;
|
|
805
|
+
return total.bytes;
|
|
806
|
+
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
_countCacheBytes( bytes ) {
|
|
810
|
+
|
|
811
|
+
if ( this._cacheTotal ) this._cacheTotal.bytes += bytes;
|
|
812
|
+
|
|
813
|
+
}
|
|
814
|
+
|
|
778
815
|
async _cacheEntries() {
|
|
779
816
|
|
|
780
817
|
const out = [];
|
|
@@ -816,8 +853,8 @@ export class StorageManager extends Emitter {
|
|
|
816
853
|
|
|
817
854
|
const entries = await this._cacheEntries();
|
|
818
855
|
const budget = await this.budget();
|
|
819
|
-
|
|
820
|
-
const target = freeBytes ?? Math.max( 0,
|
|
856
|
+
const total = this._cacheTotal = { at: Date.now(), bytes: entries.reduce( ( n, e ) => n + ( e.meta.bytes ?? 0 ), 0 ), ready: null };
|
|
857
|
+
const target = freeBytes ?? Math.max( 0, total.bytes - budget );
|
|
821
858
|
if ( target <= 0 ) return 0;
|
|
822
859
|
|
|
823
860
|
const held = await heldLockNames();
|
|
@@ -832,7 +869,7 @@ export class StorageManager extends Emitter {
|
|
|
832
869
|
if ( await area.removeById( meta.id ) ) {
|
|
833
870
|
|
|
834
871
|
freed += meta.bytes ?? 0;
|
|
835
|
-
|
|
872
|
+
total.bytes -= meta.bytes ?? 0;
|
|
836
873
|
|
|
837
874
|
}
|
|
838
875
|
|
|
@@ -855,8 +892,7 @@ export class StorageManager extends Emitter {
|
|
|
855
892
|
const free = bytes + FREE_MARGIN - ( quota - usage );
|
|
856
893
|
if ( kind !== STORAGE_KIND.CACHE ) return { free, budget: 0 };
|
|
857
894
|
|
|
858
|
-
|
|
859
|
-
return { free, budget: cacheBytes + bytes - await this.budget() };
|
|
895
|
+
return { free, budget: await this._cacheBytes() + bytes - await this.budget() };
|
|
860
896
|
|
|
861
897
|
};
|
|
862
898
|
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export const STORAGE_KIND = Object.freeze( { CACHE: 'cache', USER: 'user', SCRATCH: 'scratch' } );
|
|
2
|
+
|
|
3
|
+
/** Areas the engine itself writes; hosts define their own with `defineArea`. */
|
|
4
|
+
export const ENGINE_AREAS = Object.freeze( { DOWNLOADS: 'downloads', ARCHIVES: 'archives', SCENES: 'scenes', CDF: 'cdf', SPILL: 'spill' } );
|