rayzee 10.0.0 → 11.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 +252 -44
- package/dist/ActiveColor-YvuQq44O.js +13 -0
- package/dist/ArchiveImporter-Hn35o6Z5.js +5145 -0
- package/dist/AssetConfig-DSEntE65.js +30 -0
- package/dist/BidirectionalIntegrator-CBw8hkeu.js +946 -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-BzNpiVHZ.js} +8 -6
- package/dist/{NeuralSuperRes-PkgDLQcD.js → NeuralSuperRes-Bk7bHg2B.js} +55 -120
- package/dist/PathTracer-72XufKAr.js +29976 -0
- package/dist/PhysicalSky-BgjdV88k.js +1219 -0
- package/dist/RayzeeRenderer-1QRO97eq.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-tnAoUL1j.js +94 -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-C67jbci-.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 +20 -7
- package/src/Processor/ArchiveImporter.js +1265 -0
- package/src/Processor/ArchiveReader.js +22 -4
- 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 +254 -42
- package/src/Processor/PBRT/PBRTParser.js +49 -19
- package/src/Processor/PBRT/PBRTScattering.js +93 -0
- package/src/Processor/PBRT/PBRTSceneBuilder.js +1050 -75
- package/src/Processor/PBRT/PBRTTextureBake.js +179 -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/SceneMetadata.js +30 -5
- 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 +3900 -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 +336 -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 +208 -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 +167 -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 +180 -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 +224 -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 +985 -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 +838 -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,6 +10,23 @@
|
|
|
10
10
|
import { AnimationMixer, EventDispatcher, Timer, Vector3, LoopRepeat, LoopOnce, PropertyBinding } from 'three';
|
|
11
11
|
import { EngineEvents } from '../EngineEvents.js';
|
|
12
12
|
|
|
13
|
+
/** The nodes of `nodes` with no ancestor in it, or null when updating each would cost more than one pass over `root`. */
|
|
14
|
+
function subtreeRoots( nodes, root ) {
|
|
15
|
+
|
|
16
|
+
const roots = [ ...nodes ].filter( node => {
|
|
17
|
+
|
|
18
|
+
for ( let o = node.parent; o; o = o.parent ) if ( nodes.has( o ) ) return false;
|
|
19
|
+
return true;
|
|
20
|
+
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
let total = 0, covered = 0;
|
|
24
|
+
root.traverse?.( () => total ++ );
|
|
25
|
+
for ( const node of roots ) node.traverse?.( () => covered ++ );
|
|
26
|
+
return covered + roots.length / 2 < total ? roots : null;
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
13
30
|
export class AnimationManager extends EventDispatcher {
|
|
14
31
|
|
|
15
32
|
constructor() {
|
|
@@ -39,6 +56,8 @@ export class AnimationManager extends EventDispatcher {
|
|
|
39
56
|
this._slotOf = null; // meshIndex -> row in the two caches below, or -1
|
|
40
57
|
this._lastWorld = null; // world matrix last handed to applyPoseCallback, 16 per row
|
|
41
58
|
this._lastVisible = null; // 0 / 1, or 2 before the first pose
|
|
59
|
+
this._lastMeshWorld = null; // deforming clips: world matrix at each mesh's last read, 16 per mesh
|
|
60
|
+
this._lastMorphWeights = null;
|
|
42
61
|
|
|
43
62
|
/** Injected by PathTracerApp — wakes the render loop after play/resume. */
|
|
44
63
|
this.wakeCallback = null;
|
|
@@ -135,6 +154,8 @@ export class AnimationManager extends EventDispatcher {
|
|
|
135
154
|
// 9 floats × every triangle — 1,030 MB at 30M, past what a renderer can allocate.
|
|
136
155
|
this._skinnedCache = [];
|
|
137
156
|
this._meshPositions = [];
|
|
157
|
+
this._lastMeshWorld = this._rigid ? null : new Float64Array( meshes.length * 16 ).fill( NaN );
|
|
158
|
+
this._lastMorphWeights = [];
|
|
138
159
|
|
|
139
160
|
const skinnedCount = meshes.filter( m => m.isSkinnedMesh ).length;
|
|
140
161
|
console.debug( `[AnimationManager] Init: ${animations.length} clips, ${meshes.length} meshes (${skinnedCount} skinned), ${offset} triangles, ${this._rigid ? 'rigid' : 'deforming'}` );
|
|
@@ -158,11 +179,19 @@ export class AnimationManager extends EventDispatcher {
|
|
|
158
179
|
|
|
159
180
|
const animated = new Set();
|
|
160
181
|
let visibility = false;
|
|
182
|
+
let unresolved = false;
|
|
161
183
|
for ( const track of clip.tracks ) {
|
|
162
184
|
|
|
163
185
|
const { nodeName, propertyName } = PropertyBinding.parseTrackName( track.name );
|
|
164
|
-
|
|
165
|
-
|
|
186
|
+
// As PropertyBinding.findNode: no node name binds the root itself.
|
|
187
|
+
const node = nodeName === '' || nodeName === '.' ? root : byName.get( nodeName );
|
|
188
|
+
if ( ! node ) {
|
|
189
|
+
|
|
190
|
+
unresolved = true;
|
|
191
|
+
continue;
|
|
192
|
+
|
|
193
|
+
}
|
|
194
|
+
|
|
166
195
|
animated.add( node );
|
|
167
196
|
if ( propertyName === 'visible' ) visibility = true;
|
|
168
197
|
|
|
@@ -187,7 +216,7 @@ export class AnimationManager extends EventDispatcher {
|
|
|
187
216
|
const cameras = new Set();
|
|
188
217
|
for ( const node of animated ) node.traverse( o => o.isCamera && cameras.add( o ) );
|
|
189
218
|
|
|
190
|
-
return { meshes: Int32Array.from( meshes ), visibility, cameras: [ ...cameras ] };
|
|
219
|
+
return { meshes: Int32Array.from( meshes ), visibility, cameras: [ ...cameras ], nodes: unresolved ? null : animated, roots: unresolved ? null : subtreeRoots( animated, root ) };
|
|
191
220
|
|
|
192
221
|
} );
|
|
193
222
|
|
|
@@ -214,15 +243,18 @@ export class AnimationManager extends EventDispatcher {
|
|
|
214
243
|
|
|
215
244
|
const meshes = new Set(), cameras = new Set();
|
|
216
245
|
let visibility = false;
|
|
246
|
+
let nodes = new Set();
|
|
217
247
|
for ( const plan of this._plans ) {
|
|
218
248
|
|
|
219
249
|
plan.meshes.forEach( m => meshes.add( m ) );
|
|
220
250
|
plan.cameras.forEach( c => cameras.add( c ) );
|
|
221
251
|
visibility ||= plan.visibility;
|
|
252
|
+
if ( nodes && plan.nodes ) plan.nodes.forEach( n => nodes.add( n ) );
|
|
253
|
+
else nodes = null;
|
|
222
254
|
|
|
223
255
|
}
|
|
224
256
|
|
|
225
|
-
this._allPlan = { meshes: Int32Array.from( meshes ), visibility, cameras: [ ...cameras ] };
|
|
257
|
+
this._allPlan = { meshes: Int32Array.from( meshes ), visibility, cameras: [ ...cameras ], nodes, roots: nodes ? subtreeRoots( nodes, this._mixerRoot ) : null };
|
|
226
258
|
|
|
227
259
|
}
|
|
228
260
|
|
|
@@ -487,7 +519,10 @@ export class AnimationManager extends EventDispatcher {
|
|
|
487
519
|
|
|
488
520
|
// Bones live outside mesh subtrees so per-mesh updateMatrixWorld() misses them. Doing it
|
|
489
521
|
// once here, on mixerRoot rather than the scene, keeps unrelated static objects out of it.
|
|
490
|
-
|
|
522
|
+
// A rigid clip moves only what its tracks name, so only those subtrees are updated.
|
|
523
|
+
const roots = this._rigid ? this._planFor( this._activeClip )?.roots : null;
|
|
524
|
+
if ( roots ) for ( const node of roots ) node.updateMatrixWorld( true );
|
|
525
|
+
else this._mixerRoot.updateMatrixWorld( true );
|
|
491
526
|
|
|
492
527
|
if ( this._rigid ) {
|
|
493
528
|
|
|
@@ -499,7 +534,52 @@ export class AnimationManager extends EventDispatcher {
|
|
|
499
534
|
const cameras = this._planFor( this._activeClip )?.cameras;
|
|
500
535
|
if ( cameras?.length ) this.applyPoseCallback?.( { meshIndices: [], visibilityChanged: false, cameras } );
|
|
501
536
|
|
|
502
|
-
|
|
537
|
+
// Decided once per reader: an expanded instanced emitter asks for one mesh several times.
|
|
538
|
+
const moved = new Int8Array( this._meshes.length );
|
|
539
|
+
return m => {
|
|
540
|
+
|
|
541
|
+
if ( moved[ m ] === 0 ) moved[ m ] = this._meshes[ m ].isSkinnedMesh || this._poseChanged( m ) ? 1 : - 1;
|
|
542
|
+
return moved[ m ] > 0 ? this._computeMeshPositions( m ) : null;
|
|
543
|
+
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/** Whether a mesh's world matrix or morph weights differ from when its positions were last read. @private */
|
|
549
|
+
_poseChanged( m ) {
|
|
550
|
+
|
|
551
|
+
const mesh = this._meshes[ m ];
|
|
552
|
+
const last = this._lastMeshWorld;
|
|
553
|
+
const e = mesh.matrixWorld.elements;
|
|
554
|
+
const o = m * 16;
|
|
555
|
+
let changed = false;
|
|
556
|
+
|
|
557
|
+
for ( let i = 0; i < 16; i ++ ) {
|
|
558
|
+
|
|
559
|
+
if ( last[ o + i ] !== e[ i ] ) {
|
|
560
|
+
|
|
561
|
+
for ( let j = 0; j < 16; j ++ ) last[ o + j ] = e[ j ];
|
|
562
|
+
changed = true;
|
|
563
|
+
break;
|
|
564
|
+
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const weights = mesh.morphTargetInfluences;
|
|
570
|
+
if ( weights?.length ) {
|
|
571
|
+
|
|
572
|
+
const lastWeights = this._lastMorphWeights[ m ];
|
|
573
|
+
if ( ! lastWeights || lastWeights.length !== weights.length || lastWeights.some( ( w, i ) => w !== weights[ i ] ) ) {
|
|
574
|
+
|
|
575
|
+
this._lastMorphWeights[ m ] = Float64Array.from( weights );
|
|
576
|
+
changed = true;
|
|
577
|
+
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return changed;
|
|
503
583
|
|
|
504
584
|
}
|
|
505
585
|
|
|
@@ -640,6 +720,8 @@ export class AnimationManager extends EventDispatcher {
|
|
|
640
720
|
this._slotOf = null;
|
|
641
721
|
this._lastWorld = null;
|
|
642
722
|
this._lastVisible = null;
|
|
723
|
+
this._lastMeshWorld = null;
|
|
724
|
+
this._lastMorphWeights = null;
|
|
643
725
|
|
|
644
726
|
}
|
|
645
727
|
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import { EventDispatcher, MathUtils, OrthographicCamera, PerspectiveCamera, Quaternion, Vector3 } from 'three';
|
|
1
|
+
import { EventDispatcher, MathUtils, Matrix4, OrthographicCamera, PerspectiveCamera, Quaternion, Vector3 } from 'three';
|
|
2
2
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
3
3
|
import { EngineEvents, } from '../EngineEvents.js';
|
|
4
|
-
import {
|
|
4
|
+
import { CAMERA_PROJECTION_IDS } from '../EngineDefaults.js';
|
|
5
5
|
import { viewDepth } from './InteractionManager.js';
|
|
6
6
|
import { ViewCamera } from './ViewCamera.js';
|
|
7
7
|
import { WalkControls } from './WalkControls.js';
|
|
8
8
|
import { toPortable, fromPortable } from '../SceneState/portable.js';
|
|
9
9
|
|
|
10
|
+
export const AUTO_FOCUS_DEFAULTS = {
|
|
11
|
+
autoFocusMode: 'auto', // 'manual' | 'auto'
|
|
12
|
+
afScreenPoint: { x: 0.5, y: 0.5 },
|
|
13
|
+
afSmoothingFactor: 0.15,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const AF_RESET_THRESHOLD = 0.05;
|
|
17
|
+
const AF_FALLBACK_DISTANCE = 10.0;
|
|
18
|
+
const AF_SNAP_THRESHOLD = 0.5;
|
|
19
|
+
|
|
10
20
|
const DEFAULT_CAMERA_SCALE = Object.freeze( new Vector3( 1, 1, 1 ) );
|
|
11
21
|
|
|
12
22
|
/** The height of an orthographic camera's view in world units, or null for any other camera. */
|
|
@@ -55,13 +65,14 @@ export class CameraManager extends EventDispatcher {
|
|
|
55
65
|
this._userCameraCounter = 0;
|
|
56
66
|
|
|
57
67
|
// Auto-focus state
|
|
58
|
-
this.autoFocusMode =
|
|
59
|
-
this.afScreenPoint = {
|
|
60
|
-
this.afSmoothingFactor =
|
|
68
|
+
this.autoFocusMode = AUTO_FOCUS_DEFAULTS.autoFocusMode;
|
|
69
|
+
this.afScreenPoint = { ...AUTO_FOCUS_DEFAULTS.afScreenPoint };
|
|
70
|
+
this.afSmoothingFactor = AUTO_FOCUS_DEFAULTS.afSmoothingFactor;
|
|
61
71
|
this._lastValidFocusDistance = null;
|
|
62
72
|
this._smoothedFocusDistance = null;
|
|
63
73
|
this._afPointDirty = false;
|
|
64
74
|
this._afSuspended = false;
|
|
75
|
+
this._afPick = null;
|
|
65
76
|
|
|
66
77
|
// Saved state for default camera when switching to model cameras
|
|
67
78
|
this._defaultCameraState = null;
|
|
@@ -311,40 +322,7 @@ export class CameraManager extends EventDispatcher {
|
|
|
311
322
|
|
|
312
323
|
} else {
|
|
313
324
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
this.camera.position.copy( sourceCamera.position );
|
|
317
|
-
this.camera.quaternion.copy( sourceCamera.quaternion );
|
|
318
|
-
// An imported camera can carry a mirror (a negative axis scale) that no
|
|
319
|
-
// quaternion can express — a pbrt scene's `Scale -1 1 1`, for one. Copying
|
|
320
|
-
// pose alone would silently un-mirror the view.
|
|
321
|
-
this.camera.scale.copy( sourceCamera.scale );
|
|
322
|
-
if ( sourceCamera.isPerspectiveCamera ) this.camera.fov = sourceCamera.fov;
|
|
323
|
-
this.camera.near = sourceCamera.near;
|
|
324
|
-
this.camera.far = sourceCamera.far;
|
|
325
|
-
this.camera.updateProjectionMatrix();
|
|
326
|
-
this.camera.updateMatrixWorld( true );
|
|
327
|
-
|
|
328
|
-
// Restore the saved orbit target for user cameras; otherwise place it
|
|
329
|
-
// along the forward direction at the focus distance.
|
|
330
|
-
if ( this.controls ) {
|
|
331
|
-
|
|
332
|
-
const savedTarget = sourceCamera.userData?.__rayzeeOrbitTarget;
|
|
333
|
-
if ( savedTarget ) {
|
|
334
|
-
|
|
335
|
-
this.controls.target.copy( savedTarget );
|
|
336
|
-
|
|
337
|
-
} else {
|
|
338
|
-
|
|
339
|
-
const forward = new Vector3( 0, 0, - 1 ).applyQuaternion( sourceCamera.quaternion );
|
|
340
|
-
const focusDist = focusDistance || 5.0;
|
|
341
|
-
this.controls.target.copy( this.camera.position ).addScaledVector( forward, focusDist );
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
this.controls.update();
|
|
346
|
-
|
|
347
|
-
}
|
|
325
|
+
this._placeAt( this.cameras[ index ], focusDistance );
|
|
348
326
|
|
|
349
327
|
}
|
|
350
328
|
|
|
@@ -369,6 +347,60 @@ export class CameraManager extends EventDispatcher {
|
|
|
369
347
|
|
|
370
348
|
}
|
|
371
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Puts the active camera back at the view it starts from: the default camera at the framing the
|
|
352
|
+
* model loaded with, any other at its own pose and lens. Its effects and projection stay.
|
|
353
|
+
*/
|
|
354
|
+
resetView() {
|
|
355
|
+
|
|
356
|
+
const source = this.currentCameraIndex > 0 ? this.cameras[ this.currentCameraIndex ] : null;
|
|
357
|
+
if ( ! source ) {
|
|
358
|
+
|
|
359
|
+
this.controls.reset();
|
|
360
|
+
return;
|
|
361
|
+
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
this._placeAt( source, this._getSettings?.( 'focusDistance' ) );
|
|
365
|
+
const height = orthoHeightOf( source );
|
|
366
|
+
if ( this.camera.orthographic ) this._setView( true, height ? height / 2 : this.camera.orthoHalfHeight );
|
|
367
|
+
this._onReset?.();
|
|
368
|
+
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// The view takes a camera's pose and lens, orbiting its saved target or a point ahead at the focus distance.
|
|
372
|
+
_placeAt( source, focusDistance ) {
|
|
373
|
+
|
|
374
|
+
this.camera.position.copy( source.position );
|
|
375
|
+
this.camera.quaternion.copy( source.quaternion );
|
|
376
|
+
// An imported camera can carry a mirror (a negative axis scale) that no
|
|
377
|
+
// quaternion can express — a pbrt scene's `Scale -1 1 1`, for one. Copying
|
|
378
|
+
// pose alone would silently un-mirror the view.
|
|
379
|
+
this.camera.scale.copy( source.scale );
|
|
380
|
+
if ( source.isPerspectiveCamera ) this.camera.fov = source.fov;
|
|
381
|
+
this.camera.near = source.near;
|
|
382
|
+
this.camera.far = source.far;
|
|
383
|
+
this.camera.updateProjectionMatrix();
|
|
384
|
+
this.camera.updateMatrixWorld( true );
|
|
385
|
+
|
|
386
|
+
if ( ! this.controls ) return;
|
|
387
|
+
|
|
388
|
+
const savedTarget = source.userData?.__rayzeeOrbitTarget;
|
|
389
|
+
if ( savedTarget ) {
|
|
390
|
+
|
|
391
|
+
this.controls.target.copy( savedTarget );
|
|
392
|
+
|
|
393
|
+
} else {
|
|
394
|
+
|
|
395
|
+
const forward = new Vector3( 0, 0, - 1 ).applyQuaternion( source.quaternion );
|
|
396
|
+
this.controls.target.copy( this.camera.position ).addScaledVector( forward, focusDistance || 5.0 );
|
|
397
|
+
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
this.controls.update();
|
|
401
|
+
|
|
402
|
+
}
|
|
403
|
+
|
|
372
404
|
/**
|
|
373
405
|
* Makes the camera orthographic at `height`, or perspective for null, then hands the `cameraProjection`
|
|
374
406
|
* setting the outcome — after, so its handler finds the camera already there. A 360° panorama stays on
|
|
@@ -833,13 +865,12 @@ export class CameraManager extends EventDispatcher {
|
|
|
833
865
|
&& stage.frameCount > 0
|
|
834
866
|
&& ! stage.isComplete ) return;
|
|
835
867
|
|
|
836
|
-
|
|
837
|
-
const validHit = this.interactionManager.pickSurface( this.afScreenPoint.x * 2 - 1, 1 - this.afScreenPoint.y * 2 );
|
|
868
|
+
const hitPoint = this._pickFocusPoint( stage.resetCount );
|
|
838
869
|
|
|
839
870
|
let rawDistance;
|
|
840
|
-
if (
|
|
871
|
+
if ( hitPoint ) {
|
|
841
872
|
|
|
842
|
-
rawDistance = viewDepth(
|
|
873
|
+
rawDistance = viewDepth( hitPoint, this.camera );
|
|
843
874
|
this._lastValidFocusDistance = rawDistance;
|
|
844
875
|
|
|
845
876
|
} else {
|
|
@@ -852,7 +883,7 @@ export class CameraManager extends EventDispatcher {
|
|
|
852
883
|
|
|
853
884
|
// Nothing under the AF point on a fresh view: focus where the camera orbits.
|
|
854
885
|
const depth = this.controls ? viewDepth( this.controls.target, this.camera ) : 0;
|
|
855
|
-
rawDistance = depth > 0 ? depth :
|
|
886
|
+
rawDistance = depth > 0 ? depth : AF_FALLBACK_DISTANCE * ( assetLoader?.getSceneScale() || 1.0 );
|
|
856
887
|
this._lastValidFocusDistance = rawDistance;
|
|
857
888
|
|
|
858
889
|
}
|
|
@@ -872,7 +903,7 @@ export class CameraManager extends EventDispatcher {
|
|
|
872
903
|
const changeFraction = Math.abs( rawDistance - this._smoothedFocusDistance )
|
|
873
904
|
/ this._smoothedFocusDistance;
|
|
874
905
|
|
|
875
|
-
if ( changeFraction >
|
|
906
|
+
if ( changeFraction > AF_SNAP_THRESHOLD ) {
|
|
876
907
|
|
|
877
908
|
this._smoothedFocusDistance = rawDistance;
|
|
878
909
|
|
|
@@ -900,7 +931,7 @@ export class CameraManager extends EventDispatcher {
|
|
|
900
931
|
|
|
901
932
|
hardReset?.();
|
|
902
933
|
|
|
903
|
-
} else if ( changeRatio >
|
|
934
|
+
} else if ( changeRatio > AF_RESET_THRESHOLD ) {
|
|
904
935
|
|
|
905
936
|
softReset?.();
|
|
906
937
|
|
|
@@ -910,6 +941,32 @@ export class CameraManager extends EventDispatcher {
|
|
|
910
941
|
|
|
911
942
|
}
|
|
912
943
|
|
|
944
|
+
/** Picks again only on a new view or AF point, or a render reset, which every scene change makes. @private */
|
|
945
|
+
_pickFocusPoint( resetCount ) {
|
|
946
|
+
|
|
947
|
+
const camera = this.camera;
|
|
948
|
+
const { x, y } = this.afScreenPoint;
|
|
949
|
+
const last = this._afPick ??= { point: new Vector3(), hit: false, resetCount: NaN, x: NaN, y: NaN, view: new Matrix4(), projection: new Matrix4() };
|
|
950
|
+
|
|
951
|
+
if ( this._afPointDirty || resetCount !== last.resetCount || x !== last.x || y !== last.y
|
|
952
|
+
|| ! last.view.equals( camera.matrixWorld ) || ! last.projection.equals( camera.projectionMatrix ) ) {
|
|
953
|
+
|
|
954
|
+
// AF screen point (0 to 1, y down) to NDC.
|
|
955
|
+
const hit = this.interactionManager.pickSurface( x * 2 - 1, 1 - y * 2 );
|
|
956
|
+
last.hit = !! hit;
|
|
957
|
+
if ( hit ) last.point.copy( hit.point );
|
|
958
|
+
last.resetCount = resetCount;
|
|
959
|
+
last.x = x;
|
|
960
|
+
last.y = y;
|
|
961
|
+
last.view.copy( camera.matrixWorld );
|
|
962
|
+
last.projection.copy( camera.projectionMatrix );
|
|
963
|
+
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
return last.hit ? last.point : null;
|
|
967
|
+
|
|
968
|
+
}
|
|
969
|
+
|
|
913
970
|
/**
|
|
914
971
|
* Deferred dependency injection — InteractionManager needs the camera
|
|
915
972
|
* in its constructor, so it can't be passed during CameraManager creation.
|
|
@@ -9,7 +9,10 @@ import { createLogger } from '../utils/Logger.js';
|
|
|
9
9
|
// The neural passes live in `../neural/` but report through the manager that drives them, so they
|
|
10
10
|
// share one namespace: `rayzee.log.only( 'neural' )` shows the whole chain.
|
|
11
11
|
const neuralLog = createLogger( 'neural' );
|
|
12
|
-
import {
|
|
12
|
+
import { CAMERA_PROJECTION_IDS } from '../EngineDefaults.js';
|
|
13
|
+
import {
|
|
14
|
+
DENOISER_DEFAULTS, ASVGF_QUALITY_PRESETS, NRD_DEFAULTS, NRD_QUALITY_PRESETS, NRD_PRESET_KEYS,
|
|
15
|
+
} from '../Stages/DenoiserSettings.js';
|
|
13
16
|
|
|
14
17
|
// A refresh slower than this is a slideshow, not a live view, so the cadence swaps to a cheaper
|
|
15
18
|
// model and puts the chosen one back for the finished image. Resolution-aware by construction:
|
|
@@ -135,13 +138,13 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
135
138
|
|
|
136
139
|
// The tier the finished image uses. The loaded tier is not always this one: while the
|
|
137
140
|
// image is still accumulating we run a cheaper model (see previewQuality).
|
|
138
|
-
this._finalQuality =
|
|
141
|
+
this._finalQuality = DENOISER_DEFAULTS.oidnQuality;
|
|
139
142
|
// Two independent decisions. `finalDenoise` is the OIDN pass on the finished image;
|
|
140
143
|
// `continuousDenoise` is OIDN as the live-view denoiser. `denoiser.enabled` means only
|
|
141
144
|
// "OIDN is in use at all", which is what the aux G-buffer wiring needs.
|
|
142
|
-
this.finalDenoise =
|
|
143
|
-
this.continuousDenoise =
|
|
144
|
-
this.continuousDenoiseInterval =
|
|
145
|
+
this.finalDenoise = DENOISER_DEFAULTS.enableOIDN;
|
|
146
|
+
this.continuousDenoise = DENOISER_DEFAULTS.continuousDenoise;
|
|
147
|
+
this.continuousDenoiseInterval = DENOISER_DEFAULTS.continuousDenoiseInterval;
|
|
145
148
|
// -Infinity, not 0: 0 reads as "denoised at time zero", which blocks the first cadence
|
|
146
149
|
// denoise while performance.now() is still below the interval.
|
|
147
150
|
this._lastCadenceAt = - Infinity;
|
|
@@ -160,7 +163,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
160
163
|
this._onPostProcessRefresh = null;
|
|
161
164
|
this._onDisplayRefresh = null;
|
|
162
165
|
|
|
163
|
-
this.temporalHistory =
|
|
166
|
+
this.temporalHistory = DENOISER_DEFAULTS.oidnTemporalHistory;
|
|
164
167
|
this._history = null;
|
|
165
168
|
// Stale after a scene-changing reset, or one the app did not announce (material/env edits).
|
|
166
169
|
this._historyDirty = true;
|
|
@@ -307,7 +310,8 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
307
310
|
// Compositor decides what the single canvas shows. The exposure, grade and tone curve
|
|
308
311
|
// come from the renderer's own output pass, so it is not told about them either.
|
|
309
312
|
this.denoiser = new OIDNDenoiser( this.renderer, {
|
|
310
|
-
|
|
313
|
+
enableOIDN: DENOISER_DEFAULTS.enableOIDN,
|
|
314
|
+
oidnQuality: DENOISER_DEFAULTS.oidnQuality,
|
|
311
315
|
|
|
312
316
|
backendParams: () => ( {
|
|
313
317
|
device: this.renderer.backend.device,
|
|
@@ -378,8 +382,8 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
378
382
|
const pt = this._stages.pathTracer;
|
|
379
383
|
|
|
380
384
|
this.upscaler = new AIUpscaler( this.upscalerCanvas, this.renderer, {
|
|
381
|
-
scaleFactor:
|
|
382
|
-
quality:
|
|
385
|
+
scaleFactor: DENOISER_DEFAULTS.upscalerScale || 2,
|
|
386
|
+
quality: DENOISER_DEFAULTS.upscalerQuality || 'fast',
|
|
383
387
|
|
|
384
388
|
// One source: the render canvas shows whatever the Compositor picked — the denoised
|
|
385
389
|
// picture when OIDN is on, the raw render otherwise — so the upscaler always enlarges
|
|
@@ -407,7 +411,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
407
411
|
getSaturation: () => this._getSaturation(),
|
|
408
412
|
} );
|
|
409
413
|
|
|
410
|
-
this.upscaler.enabled =
|
|
414
|
+
this.upscaler.enabled = DENOISER_DEFAULTS.enableUpscaler || false;
|
|
411
415
|
|
|
412
416
|
// Forward lifecycle events (store refs for removal on re-setup / dispose)
|
|
413
417
|
this._upscalerResChangedHandler = ( e ) =>
|