rayzee 8.8.2 → 9.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 +71 -12
- package/dist/{NeuralSuperRes-Dc6jRYke.js → NeuralSuperRes-CQLCLpcC.js} +2 -0
- package/dist/rayzee.es.js +3571 -3110
- package/dist/rayzee.umd.js +110 -99
- package/package.json +1 -1
- package/src/EngineDefaults.js +21 -19
- package/src/EngineEvents.js +4 -0
- package/src/Passes/OIDNTemporalHistory.js +25 -7
- package/src/PathTracerApp.js +23 -6
- package/src/Processor/AssetLoader.js +9 -0
- package/src/Processor/PBRT/PBRTSceneBuilder.js +18 -6
- package/src/RenderSettings.js +11 -8
- package/src/Stages/MotionVector.js +8 -42
- package/src/Stages/NRD.js +30 -21
- package/src/Stages/NormalDepth.js +5 -17
- package/src/Stages/PathTracer.js +6 -2
- package/src/TSL/CameraRay.js +99 -14
- package/src/TSL/DebugKernel.js +2 -2
- package/src/TSL/GenerateKernel.js +2 -2
- package/src/index.js +4 -0
- package/src/managers/CameraManager.js +244 -56
- package/src/managers/DenoisingManager.js +4 -3
- package/src/managers/InteractionManager.js +30 -2
- package/src/managers/UniformManager.js +6 -4
- package/src/managers/VideoRenderManager.js +35 -16
- package/src/managers/ViewCamera.js +77 -0
- package/src/managers/WalkControls.js +262 -0
- package/src/managers/helpers/OutlineHelper.js +22 -2
- package/src/managers/timeline/CameraTrack.js +213 -0
- package/src/managers/timeline/TimelineManager.js +132 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { InterpolateSmooth, MathUtils, NumberKeyframeTrack, Vector3, VectorKeyframeTrack } from 'three';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} CameraPose
|
|
5
|
+
* @property {Vector3} position
|
|
6
|
+
* @property {Vector3} target - what the camera looks at
|
|
7
|
+
* @property {number} fov - vertical, degrees
|
|
8
|
+
* @property {number} orthoHeight - the view's height while orthographic, world units
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** @typedef {CameraPose & { id: number, time: number }} CameraKey */
|
|
12
|
+
|
|
13
|
+
// Keys closer than this in time are spread to it: an interval of zero divides by zero.
|
|
14
|
+
const MIN_KEY_GAP = 1e-3;
|
|
15
|
+
// Where a new key lands after the last one.
|
|
16
|
+
const KEY_SPACING_SECONDS = 2;
|
|
17
|
+
|
|
18
|
+
const smooth = ( Track, name, times, values ) => new Track( name, times, values, InterpolateSmooth ).createInterpolant();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The camera's keyframes: each a view at a time, in seconds. Between keys the camera glides along a
|
|
22
|
+
* curve through their positions while looking along one through their targets; outside them it holds.
|
|
23
|
+
* The orthographic height blends in log space, so a zoom reads as steady.
|
|
24
|
+
*/
|
|
25
|
+
export class CameraTrack {
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {import('../CameraManager.js').CameraManager} cameraManager - where views come from and go
|
|
29
|
+
* @param {Function} [onChange] - after keys are added, moved, changed or removed
|
|
30
|
+
*/
|
|
31
|
+
constructor( cameraManager, onChange ) {
|
|
32
|
+
|
|
33
|
+
this._cameraManager = cameraManager;
|
|
34
|
+
this._onChange = onChange;
|
|
35
|
+
|
|
36
|
+
/** @type {CameraKey[]} sorted by time */
|
|
37
|
+
this.keys = [];
|
|
38
|
+
this._nextId = 1;
|
|
39
|
+
this._interpolants = null;
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Two keys or more: one is only a still view. */
|
|
44
|
+
get animates() {
|
|
45
|
+
|
|
46
|
+
return this.keys.length > 1;
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Seconds from 0 to the last key. */
|
|
51
|
+
get duration() {
|
|
52
|
+
|
|
53
|
+
return this.keys.length ? this.keys[ this.keys.length - 1 ].time : 0;
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Keys the current view, KEY_SPACING_SECONDS after the last key unless given a time.
|
|
59
|
+
* @param {number} [time]
|
|
60
|
+
* @returns {CameraKey}
|
|
61
|
+
*/
|
|
62
|
+
addKey( time = this.keys.length ? this.duration + KEY_SPACING_SECONDS : 0 ) {
|
|
63
|
+
|
|
64
|
+
return this.add( this._cameraManager.captureView(), time );
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Gives a key the current view, at the same time. */
|
|
69
|
+
updateKey( id ) {
|
|
70
|
+
|
|
71
|
+
this.update( id, this._cameraManager.captureView() );
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Puts the camera where the track has it at `time`.
|
|
77
|
+
* @returns {boolean} whether there was a key to go to
|
|
78
|
+
*/
|
|
79
|
+
seek( time ) {
|
|
80
|
+
|
|
81
|
+
const pose = this.sample( time );
|
|
82
|
+
if ( pose ) this._cameraManager.applyPose( pose );
|
|
83
|
+
return !! pose;
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {CameraPose} pose - copied
|
|
89
|
+
* @param {number} time
|
|
90
|
+
* @returns {CameraKey}
|
|
91
|
+
*/
|
|
92
|
+
add( pose, time ) {
|
|
93
|
+
|
|
94
|
+
const key = { id: this._nextId ++, time, ...copyPose( pose ) };
|
|
95
|
+
this.keys.push( key );
|
|
96
|
+
this._changed();
|
|
97
|
+
return key;
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Gives the key a new pose, at the same time. */
|
|
102
|
+
update( id, pose ) {
|
|
103
|
+
|
|
104
|
+
const key = this.get( id );
|
|
105
|
+
if ( ! key ) return;
|
|
106
|
+
Object.assign( key, copyPose( pose ) );
|
|
107
|
+
this._changed();
|
|
108
|
+
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
setTime( id, time ) {
|
|
112
|
+
|
|
113
|
+
const key = this.get( id );
|
|
114
|
+
if ( ! key || ! ( time >= 0 ) ) return;
|
|
115
|
+
key.time = time;
|
|
116
|
+
this._changed();
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
remove( id ) {
|
|
121
|
+
|
|
122
|
+
const count = this.keys.length;
|
|
123
|
+
this.keys = this.keys.filter( key => key.id !== id );
|
|
124
|
+
if ( this.keys.length !== count ) this._changed();
|
|
125
|
+
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
clear() {
|
|
129
|
+
|
|
130
|
+
if ( ! this.keys.length ) return;
|
|
131
|
+
this.keys = [];
|
|
132
|
+
this._changed();
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
dispose() {
|
|
137
|
+
|
|
138
|
+
this._cameraManager = this._onChange = null;
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get( id ) {
|
|
143
|
+
|
|
144
|
+
return this.keys.find( key => key.id === id );
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The pose at `time`, in seconds; null without keys.
|
|
150
|
+
* @param {number} time
|
|
151
|
+
* @param {CameraPose} [out]
|
|
152
|
+
* @returns {?CameraPose}
|
|
153
|
+
*/
|
|
154
|
+
sample( time, out = { position: new Vector3(), target: new Vector3(), fov: 0, orthoHeight: 0 } ) {
|
|
155
|
+
|
|
156
|
+
if ( ! this.keys.length ) return null;
|
|
157
|
+
|
|
158
|
+
const { position, target, fov, logHeight, start, end } = this._interpolants ??= this._build();
|
|
159
|
+
const at = MathUtils.clamp( time, start, end );
|
|
160
|
+
out.position.fromArray( position.evaluate( at ) );
|
|
161
|
+
out.target.fromArray( target.evaluate( at ) );
|
|
162
|
+
out.fov = fov.evaluate( at )[ 0 ];
|
|
163
|
+
out.orthoHeight = Math.exp( logHeight.evaluate( at )[ 0 ] );
|
|
164
|
+
return out;
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
_build() {
|
|
169
|
+
|
|
170
|
+
const times = [];
|
|
171
|
+
for ( const key of this.keys ) times.push( times.length ? Math.max( key.time, times[ times.length - 1 ] + MIN_KEY_GAP ) : key.time );
|
|
172
|
+
const start = times[ 0 ];
|
|
173
|
+
const end = times[ times.length - 1 ];
|
|
174
|
+
|
|
175
|
+
// Each end gets a key mirrored past it, so the curve leaves the first key and reaches the last at
|
|
176
|
+
// rest. three's ZeroSlopeEnding would flatten only the start.
|
|
177
|
+
let keys = this.keys;
|
|
178
|
+
if ( keys.length > 1 ) {
|
|
179
|
+
|
|
180
|
+
const n = keys.length;
|
|
181
|
+
times.unshift( 2 * start - times[ 1 ] );
|
|
182
|
+
times.push( 2 * end - times[ n - 1 ] );
|
|
183
|
+
keys = [ keys[ 1 ], ...keys, keys[ n - 2 ] ];
|
|
184
|
+
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const vectors = pick => keys.flatMap( key => pick( key ).toArray() );
|
|
188
|
+
return {
|
|
189
|
+
start,
|
|
190
|
+
end,
|
|
191
|
+
position: smooth( VectorKeyframeTrack, '.position', times, vectors( key => key.position ) ),
|
|
192
|
+
target: smooth( VectorKeyframeTrack, '.target', times, vectors( key => key.target ) ),
|
|
193
|
+
fov: smooth( NumberKeyframeTrack, '.fov', times, keys.map( key => key.fov ) ),
|
|
194
|
+
logHeight: smooth( NumberKeyframeTrack, '.orthoHeight', times, keys.map( key => Math.log( key.orthoHeight ) ) ),
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
_changed() {
|
|
200
|
+
|
|
201
|
+
this.keys.sort( ( a, b ) => a.time - b.time );
|
|
202
|
+
this._interpolants = null;
|
|
203
|
+
this._onChange?.();
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function copyPose( { position, target, fov, orthoHeight } ) {
|
|
210
|
+
|
|
211
|
+
return { position: position.clone(), target: target.clone(), fov, orthoHeight };
|
|
212
|
+
|
|
213
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { EventDispatcher, MathUtils, Timer } from 'three';
|
|
2
|
+
import { EngineEvents } from '../../EngineEvents.js';
|
|
3
|
+
import { CameraTrack } from './CameraTrack.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The authored animation: keyframed tracks on one time axis, in seconds, of which the camera's
|
|
7
|
+
* ({@link CameraTrack}) is the first. A model's own clips stay with the AnimationManager.
|
|
8
|
+
*/
|
|
9
|
+
export class TimelineManager extends EventDispatcher {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {Object} deps
|
|
13
|
+
* @param {import('../CameraManager.js').CameraManager} deps.cameraManager
|
|
14
|
+
* @param {Function} deps.onReset - restarts accumulation and wakes the frame loop
|
|
15
|
+
*/
|
|
16
|
+
constructor( { cameraManager, onReset } ) {
|
|
17
|
+
|
|
18
|
+
super();
|
|
19
|
+
|
|
20
|
+
this._cameraManager = cameraManager;
|
|
21
|
+
this._onReset = onReset;
|
|
22
|
+
|
|
23
|
+
this.camera = new CameraTrack( cameraManager, () => this._changed( 'camera' ) );
|
|
24
|
+
|
|
25
|
+
this._playback = null;
|
|
26
|
+
this._timer = new Timer();
|
|
27
|
+
// A hidden page's time is not played.
|
|
28
|
+
if ( typeof document !== 'undefined' ) this._timer.connect( document );
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Seconds to the last key of any track. */
|
|
33
|
+
get duration() {
|
|
34
|
+
|
|
35
|
+
return this.camera.duration;
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get animates() {
|
|
40
|
+
|
|
41
|
+
return this.camera.animates;
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Puts the scene where the timeline has it at `time`.
|
|
47
|
+
* @param {number} time - seconds
|
|
48
|
+
* @returns {boolean} whether anything moved
|
|
49
|
+
*/
|
|
50
|
+
seek( time ) {
|
|
51
|
+
|
|
52
|
+
return this.camera.seek( time );
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Runs the timeline in the viewport from the start, with the camera controls locked. Resolves when
|
|
58
|
+
* it ends or {@link stop} is called; the scene stays where it got to.
|
|
59
|
+
* @returns {Promise<void>}
|
|
60
|
+
*/
|
|
61
|
+
play() {
|
|
62
|
+
|
|
63
|
+
this.stop();
|
|
64
|
+
return new Promise( resolve => {
|
|
65
|
+
|
|
66
|
+
const controls = this._cameraManager.controls;
|
|
67
|
+
this._playback = { elapsed: 0, resolve, controlsEnabled: controls.enabled };
|
|
68
|
+
controls.enabled = false;
|
|
69
|
+
this._timer.reset();
|
|
70
|
+
this._changed();
|
|
71
|
+
this._onReset?.();
|
|
72
|
+
|
|
73
|
+
} );
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
stop() {
|
|
78
|
+
|
|
79
|
+
const playback = this._playback;
|
|
80
|
+
if ( ! playback ) return;
|
|
81
|
+
this._playback = null;
|
|
82
|
+
this._cameraManager.controls.enabled = playback.controlsEnabled;
|
|
83
|
+
this._changed();
|
|
84
|
+
playback.resolve();
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
get isPlaying() {
|
|
89
|
+
|
|
90
|
+
return !! this._playback;
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Per frame, before the camera controls update. */
|
|
95
|
+
update() {
|
|
96
|
+
|
|
97
|
+
const playback = this._playback;
|
|
98
|
+
if ( ! playback ) return;
|
|
99
|
+
|
|
100
|
+
this._timer.update();
|
|
101
|
+
playback.elapsed += this._timer.getDelta();
|
|
102
|
+
const time = MathUtils.clamp( playback.elapsed, 0, this.duration );
|
|
103
|
+
this.seek( time );
|
|
104
|
+
if ( time >= this.duration ) this.stop();
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Drops every key: they belonged to the scene being replaced. */
|
|
109
|
+
clear() {
|
|
110
|
+
|
|
111
|
+
this.stop();
|
|
112
|
+
this.camera.clear();
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
dispose() {
|
|
117
|
+
|
|
118
|
+
this.stop();
|
|
119
|
+
this._timer.dispose();
|
|
120
|
+
this.camera.dispose();
|
|
121
|
+
this._cameraManager = this._onReset = null;
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** @param {string} [track] - whose keys changed; none for playback */
|
|
126
|
+
_changed( track ) {
|
|
127
|
+
|
|
128
|
+
this.dispatchEvent( { type: EngineEvents.TIMELINE_CHANGED, track } );
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
}
|