rayzee 9.1.2 → 9.2.1
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 +176 -16
- package/dist/{NeuralRetouch-BRquqfmZ.js → NeuralRetouch-CYgkQY8Z.js} +1 -1
- package/dist/{NeuralSuperRes-CbNvQjCw.js → NeuralSuperRes-PkgDLQcD.js} +72 -40
- package/dist/{ToneMapGPU-DpUZDMbQ.js → ToneMapGPU-B6XIe3DU.js} +102 -92
- package/dist/rayzee.es.js +6209 -5571
- package/dist/rayzee.umd.js +137 -126
- package/package.json +3 -2
- package/src/AssetConfig.js +10 -5
- package/src/EngineEvents.js +41 -1
- package/src/EngineIssues.js +3 -0
- package/src/Headless.js +23 -7
- package/src/HeadlessCanvas.js +104 -0
- package/src/Passes/OIDNDenoiser.js +29 -4
- package/src/Passes/OIDNTemporalHistory.js +7 -0
- package/src/PathTracerApp.js +511 -136
- package/src/Platform.js +76 -0
- package/src/Processor/AssetLoader.js +66 -4
- package/src/Processor/BVHBuilder.js +2 -1
- package/src/Processor/EquirectHDRInfo.js +2 -1
- package/src/Processor/HostMemory.js +14 -0
- package/src/Processor/PBRT/PBRTSceneBuilder.js +26 -0
- package/src/Processor/ParallelBVHBuilder.js +7 -6
- package/src/Processor/PlatformImageLoader.js +118 -0
- package/src/Processor/ResampleRGBA8.js +102 -0
- package/src/Processor/SceneProcessor.js +7 -6
- package/src/Processor/TextureCreator.js +162 -13
- package/src/Processor/TextureReadback.js +26 -10
- package/src/Processor/ToneMapGPU.js +45 -15
- package/src/Processor/Workers/PackWorker.js +28 -0
- package/src/Stages/Compositor.js +25 -6
- package/src/Stages/PathTracer.js +142 -25
- package/src/Stages/PathTracerStage.js +6 -96
- package/src/Storage/DownloadCache.js +30 -7
- package/src/TSL/DebugKernel.js +1 -1
- package/src/TSL/GenerateKernel.js +2 -5
- package/src/TSL/Random.js +3 -120
- package/src/TSL/ShadeKernel.js +3 -3
- package/src/index.js +2 -1
- package/src/managers/CameraManager.js +2 -2
- package/src/managers/DenoisingManager.js +76 -7
- package/src/managers/GoboManager.js +8 -1
- package/src/managers/IESManager.js +13 -2
- package/src/managers/InteractionManager.js +1 -1
- package/src/managers/LightManager.js +31 -0
- package/src/managers/OverlayManager.js +11 -1
- package/src/managers/VideoRenderManager.js +8 -0
- package/src/node/NodeWorker.js +144 -0
- package/src/node/index.js +9 -0
- package/src/node/nodePlatform.js +86 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rayzee",
|
|
3
|
-
"version": "9.1
|
|
3
|
+
"version": "9.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Real-time WebGPU path tracing engine built on Three.js",
|
|
6
6
|
"main": "dist/rayzee.umd.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"import": "./dist/rayzee.es.js",
|
|
11
11
|
"require": "./dist/rayzee.umd.js"
|
|
12
|
-
}
|
|
12
|
+
},
|
|
13
|
+
"./node": "./src/node/index.js"
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
15
16
|
"dist",
|
package/src/AssetConfig.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* Usage:
|
|
6
6
|
* import { configureAssets } from 'rayzee';
|
|
7
7
|
* configureAssets({
|
|
8
|
-
* stbnScalarAtlas: '/assets/stbn_scalar_atlas.png',
|
|
9
8
|
* dracoDecoderPath: '/draco/',
|
|
10
9
|
* cacheNamespace: 'my-app',
|
|
11
10
|
* });
|
|
@@ -14,10 +13,6 @@
|
|
|
14
13
|
*/
|
|
15
14
|
|
|
16
15
|
const config = {
|
|
17
|
-
// STBN blue-noise atlases (NVIDIA-RTX/STBN). Decoded as Float32 textures.
|
|
18
|
-
stbnScalarAtlas: 'https://assets.rayzee.atulmourya.com/noise/stbn_scalar_atlas.png',
|
|
19
|
-
stbnVec2Atlas: 'https://assets.rayzee.atulmourya.com/noise/stbn_vec2_atlas.png',
|
|
20
|
-
|
|
21
16
|
// onnxruntime-web (loaded lazily by AI upscaler worker via dynamic import).
|
|
22
17
|
ortRuntimeUrl: 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/ort.webgpu.bundle.min.mjs',
|
|
23
18
|
ortWasmPaths: 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/',
|
|
@@ -62,6 +57,8 @@ const config = {
|
|
|
62
57
|
storage: 'auto',
|
|
63
58
|
};
|
|
64
59
|
|
|
60
|
+
const configured = new Set();
|
|
61
|
+
|
|
65
62
|
/**
|
|
66
63
|
* Override asset URLs and cache namespace. Partial — only provided keys are replaced.
|
|
67
64
|
* @param {Partial<typeof config>} overrides
|
|
@@ -70,6 +67,14 @@ export function configureAssets( overrides ) {
|
|
|
70
67
|
|
|
71
68
|
if ( ! overrides ) return;
|
|
72
69
|
Object.assign( config, overrides );
|
|
70
|
+
for ( const key of Object.keys( overrides ) ) configured.add( key );
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Whether a host set this key, as opposed to it being the default. */
|
|
75
|
+
export function isAssetConfigured( key ) {
|
|
76
|
+
|
|
77
|
+
return configured.has( key );
|
|
73
78
|
|
|
74
79
|
}
|
|
75
80
|
|
package/src/EngineEvents.js
CHANGED
|
@@ -35,6 +35,9 @@ export const EngineEvents = {
|
|
|
35
35
|
TRANSFORM_MODE_CHANGED: 'engine:transformModeChanged',
|
|
36
36
|
|
|
37
37
|
// Camera
|
|
38
|
+
CAMERA_SWITCHED: 'engine:cameraSwitched',
|
|
39
|
+
CAMERAS_UPDATED: 'engine:camerasUpdated',
|
|
40
|
+
FOCUS_CHANGED: 'engine:focusChanged',
|
|
38
41
|
AUTO_FOCUS_UPDATED: 'engine:autoFocusUpdated',
|
|
39
42
|
ORTHO_HEIGHT_UPDATED: 'engine:orthoHeightUpdated',
|
|
40
43
|
AUTO_EXPOSURE_UPDATED: 'engine:autoExposureUpdated',
|
|
@@ -63,9 +66,46 @@ export const EngineEvents = {
|
|
|
63
66
|
// Degradation
|
|
64
67
|
ISSUE: 'engine:issue',
|
|
65
68
|
|
|
66
|
-
// Scene
|
|
69
|
+
// Scene and assets
|
|
70
|
+
MODEL_LOADED: 'engine:modelLoaded',
|
|
71
|
+
OBJECT3D_LOADED: 'engine:object3dLoaded',
|
|
72
|
+
MODEL_ADDED: 'engine:modelAdded',
|
|
73
|
+
SCENE_OBJECT_REMOVED: 'engine:sceneObjectRemoved',
|
|
74
|
+
SCENE_UNLOADED: 'engine:sceneUnloaded',
|
|
75
|
+
SCENE_REBUILD: 'engine:sceneRebuild',
|
|
76
|
+
SCENE_SPILLED: 'engine:sceneSpilled',
|
|
67
77
|
SCENE_METADATA_APPLIED: 'engine:sceneMetadataApplied',
|
|
78
|
+
ENVIRONMENT_LOADED: 'engine:environmentLoaded',
|
|
79
|
+
TEXTURES_REPROCESSED: 'engine:texturesReprocessed',
|
|
80
|
+
|
|
81
|
+
// Render size
|
|
82
|
+
RESOLUTION_CHANGED: 'engine:resolutionChanged',
|
|
83
|
+
RESERVED_RENDER_SIZE_CHANGED: 'engine:reservedRenderSizeChanged',
|
|
68
84
|
|
|
69
85
|
// Storage (OPFS): usage or entries changed
|
|
70
86
|
STORAGE_CHANGED: 'engine:storageChanged',
|
|
71
87
|
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The names these events had before they moved under `engine:`. The app dispatches each under both
|
|
91
|
+
* until the next major.
|
|
92
|
+
*/
|
|
93
|
+
export const LEGACY_EVENT_NAMES = Object.freeze( {
|
|
94
|
+
[ EngineEvents.RENDER_COMPLETE ]: 'RenderComplete',
|
|
95
|
+
[ EngineEvents.RENDER_RESET ]: 'RenderReset',
|
|
96
|
+
[ EngineEvents.CAMERA_SWITCHED ]: 'CameraSwitched',
|
|
97
|
+
[ EngineEvents.CAMERAS_UPDATED ]: 'CamerasUpdated',
|
|
98
|
+
[ EngineEvents.FOCUS_CHANGED ]: 'focusChanged',
|
|
99
|
+
[ EngineEvents.MODEL_LOADED ]: 'ModelLoaded',
|
|
100
|
+
[ EngineEvents.OBJECT3D_LOADED ]: 'Object3DLoaded',
|
|
101
|
+
[ EngineEvents.MODEL_ADDED ]: 'ModelAdded',
|
|
102
|
+
[ EngineEvents.SCENE_OBJECT_REMOVED ]: 'SceneObjectRemoved',
|
|
103
|
+
[ EngineEvents.SCENE_UNLOADED ]: 'SceneUnloaded',
|
|
104
|
+
[ EngineEvents.SCENE_REBUILD ]: 'SceneRebuild',
|
|
105
|
+
[ EngineEvents.SCENE_SPILLED ]: 'SceneSpilled',
|
|
106
|
+
[ EngineEvents.SCENE_METADATA_APPLIED ]: 'SceneMetadataApplied',
|
|
107
|
+
[ EngineEvents.ENVIRONMENT_LOADED ]: 'EnvironmentLoaded',
|
|
108
|
+
[ EngineEvents.TEXTURES_REPROCESSED ]: 'TexturesReprocessed',
|
|
109
|
+
[ EngineEvents.RESOLUTION_CHANGED ]: 'resolution_changed',
|
|
110
|
+
[ EngineEvents.RESERVED_RENDER_SIZE_CHANGED ]: 'reserved_render_size_changed',
|
|
111
|
+
} );
|
package/src/EngineIssues.js
CHANGED
|
@@ -30,6 +30,9 @@ export const ISSUE_CODES = Object.freeze( {
|
|
|
30
30
|
STORAGE_READ_FAILED: 'storage.read_failed',
|
|
31
31
|
STORAGE_ENTRY_CORRUPT: 'storage.entry_corrupt',
|
|
32
32
|
STORAGE_CACHE_MISMATCH: 'storage.cache_mismatch',
|
|
33
|
+
DENOISER_UNAVAILABLE: 'denoiser.unavailable',
|
|
34
|
+
OUTPUT_SOURCE_FALLBACK: 'output.source_fallback',
|
|
35
|
+
LIGHT_PLACEHOLDER_SKIPPED: 'light.placeholder_skipped',
|
|
33
36
|
} );
|
|
34
37
|
|
|
35
38
|
/** Strict throws on ERROR only. */
|
package/src/Headless.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* strict, physical profile, deterministic — all reversible, none reversible by accident.
|
|
4
4
|
*
|
|
5
5
|
* @example
|
|
6
|
-
* const shot = await renderHeadless( {
|
|
6
|
+
* const shot = await renderHeadless( { model: url, width: 1920, height: 1080, samples: 256 } );
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { PathTracerApp } from './PathTracerApp.js';
|
|
@@ -11,7 +11,9 @@ import { PathTracerApp } from './PathTracerApp.js';
|
|
|
11
11
|
* One render, start to finish, disposing the app afterwards.
|
|
12
12
|
*
|
|
13
13
|
* @param {Object} options
|
|
14
|
-
* @param {HTMLCanvasElement} options.canvas -
|
|
14
|
+
* @param {HTMLCanvasElement} [options.canvas] - leave it out and the app runs headless, on a canvas of
|
|
15
|
+
* its own (see PathTracerApp's `headless` option); pass one only to also present to it
|
|
16
|
+
* @param {number} [options.hostMemoryGB] - see PathTracerApp; needed outside Chrome for renders above 2048
|
|
15
17
|
* @param {string} [options.model] - URL to load before rendering
|
|
16
18
|
* @param {number} [options.width=1920]
|
|
17
19
|
* @param {number} [options.height=1080]
|
|
@@ -21,10 +23,12 @@ import { PathTracerApp } from './PathTracerApp.js';
|
|
|
21
23
|
* @param {string} [options.profile='physical'] - see RENDER_PROFILES
|
|
22
24
|
* @param {boolean} [options.deterministic=true]
|
|
23
25
|
* @param {boolean} [options.allowEarlyRetire=false] - needs `deterministic: false` to be reachable
|
|
26
|
+
* @param {boolean} [options.denoise=false] - one final OIDN pass, read back instead of the raw accumulation
|
|
24
27
|
* @param {Object} [options.settings] - applied after the model loads
|
|
25
28
|
* @param {function(number): void} [options.onProgress] - running sample count
|
|
26
29
|
* @returns {Promise<{data: Float32Array|Uint8ClampedArray, width: number, height: number,
|
|
27
|
-
* colorSpace: string, samples: number, retiredBy: string, issues: Object[], adapter: Object
|
|
30
|
+
* colorSpace: string, source: string, samples: number, retiredBy: string, issues: Object[], adapter: Object,
|
|
31
|
+
* provenance: Object}>} `provenance` is {@link PathTracerApp#getProvenance} at the moment of capture
|
|
28
32
|
*/
|
|
29
33
|
export async function renderHeadless( options ) {
|
|
30
34
|
|
|
@@ -51,11 +55,23 @@ export async function captureHeadless( app, {
|
|
|
51
55
|
samples = 64,
|
|
52
56
|
colorSpace = 'srgb',
|
|
53
57
|
allowEarlyRetire = false,
|
|
58
|
+
denoise = false,
|
|
54
59
|
onProgress = undefined,
|
|
55
60
|
} = {} ) {
|
|
56
61
|
|
|
62
|
+
// Before accumulating: OIDN reads the albedo and normal buffers, which are only written while it is
|
|
63
|
+
// on. Not setOIDNEnabled(), whose refresh would wake the loop; renderFrames resets anyway.
|
|
64
|
+
const dm = app.denoisingManager;
|
|
65
|
+
if ( denoise && dm && ! dm.finalDenoise ) {
|
|
66
|
+
|
|
67
|
+
dm.applyOIDNEnabled( true );
|
|
68
|
+
dm._syncGBufferStages();
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
57
72
|
const accumulated = await app.renderFrames( samples, { onProgress, allowEarlyRetire } );
|
|
58
|
-
|
|
73
|
+
if ( denoise ) await app.runFinalDenoise();
|
|
74
|
+
const frame = await app.renderToBuffer( { colorSpace, source: denoise ? 'display' : 'accumulation' } );
|
|
59
75
|
|
|
60
76
|
return {
|
|
61
77
|
...frame,
|
|
@@ -63,6 +79,7 @@ export async function captureHeadless( app, {
|
|
|
63
79
|
retiredBy: accumulated < samples ? 'converged' : 'count',
|
|
64
80
|
issues: app.issues,
|
|
65
81
|
adapter: app.adapterInfo,
|
|
82
|
+
provenance: app.getProvenance(),
|
|
66
83
|
};
|
|
67
84
|
|
|
68
85
|
}
|
|
@@ -82,12 +99,11 @@ export async function openHeadless( {
|
|
|
82
99
|
deterministic = true,
|
|
83
100
|
settings = null,
|
|
84
101
|
storage = false,
|
|
102
|
+
hostMemoryGB = undefined,
|
|
85
103
|
} = {} ) {
|
|
86
104
|
|
|
87
|
-
if ( ! canvas ) throw new Error( 'openHeadless: a canvas is required' );
|
|
88
|
-
|
|
89
105
|
// Off unless asked for: cached state from an earlier run must not change what a batch renders.
|
|
90
|
-
const app = new PathTracerApp( canvas, { autoResize: false, strict, profile, storage } );
|
|
106
|
+
const app = new PathTracerApp( canvas ?? null, { autoResize: false, strict, profile, storage, hostMemoryGB } );
|
|
91
107
|
|
|
92
108
|
try {
|
|
93
109
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A canvas for a render nobody watches. three.js reads its size and asks it for a WebGPU context;
|
|
3
|
+
* the camera controls attach listeners to it. Here the context presents into a plain texture, and
|
|
4
|
+
* the listeners go nowhere, so no document, window or swapchain is needed. Read results with
|
|
5
|
+
* `renderToBuffer()`; there is no picture to capture from it.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const inert = {
|
|
9
|
+
addEventListener() {},
|
|
10
|
+
removeEventListener() {},
|
|
11
|
+
dispatchEvent() {
|
|
12
|
+
|
|
13
|
+
return true;
|
|
14
|
+
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
class HeadlessGPUContext {
|
|
19
|
+
|
|
20
|
+
constructor( canvas ) {
|
|
21
|
+
|
|
22
|
+
this.canvas = canvas;
|
|
23
|
+
this._configuration = null;
|
|
24
|
+
this._texture = null;
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
configure( configuration ) {
|
|
29
|
+
|
|
30
|
+
this.unconfigure();
|
|
31
|
+
this._configuration = configuration;
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
unconfigure() {
|
|
36
|
+
|
|
37
|
+
this._texture?.destroy();
|
|
38
|
+
this._texture = null;
|
|
39
|
+
this._configuration = null;
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getConfiguration() {
|
|
44
|
+
|
|
45
|
+
return this._configuration;
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getCurrentTexture() {
|
|
50
|
+
|
|
51
|
+
if ( ! this._configuration ) throw new Error( 'HeadlessGPUContext: getCurrentTexture() before configure()' );
|
|
52
|
+
|
|
53
|
+
const width = Math.max( 1, this.canvas.width );
|
|
54
|
+
const height = Math.max( 1, this.canvas.height );
|
|
55
|
+
|
|
56
|
+
if ( this._texture?.width !== width || this._texture?.height !== height ) {
|
|
57
|
+
|
|
58
|
+
const { device, format, usage } = this._configuration;
|
|
59
|
+
this._texture?.destroy();
|
|
60
|
+
this._texture = device.createTexture( { label: 'headless-canvas', size: [ width, height ], format, usage } );
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return this._texture;
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {number} [width=1]
|
|
72
|
+
* @param {number} [height=1]
|
|
73
|
+
*/
|
|
74
|
+
export function createHeadlessCanvas( width = 1, height = 1 ) {
|
|
75
|
+
|
|
76
|
+
const ownerDocument = { ...inert, defaultView: null };
|
|
77
|
+
|
|
78
|
+
const canvas = {
|
|
79
|
+
...inert,
|
|
80
|
+
isHeadlessCanvas: true,
|
|
81
|
+
width,
|
|
82
|
+
height,
|
|
83
|
+
clientWidth: 0,
|
|
84
|
+
clientHeight: 0,
|
|
85
|
+
style: {},
|
|
86
|
+
parentNode: null,
|
|
87
|
+
ownerDocument,
|
|
88
|
+
getRootNode: () => ownerDocument,
|
|
89
|
+
getBoundingClientRect() {
|
|
90
|
+
|
|
91
|
+
return { x: 0, y: 0, left: 0, top: 0, right: this.width, bottom: this.height, width: this.width, height: this.height };
|
|
92
|
+
|
|
93
|
+
},
|
|
94
|
+
setPointerCapture() {},
|
|
95
|
+
releasePointerCapture() {},
|
|
96
|
+
hasPointerCapture: () => false,
|
|
97
|
+
focus() {},
|
|
98
|
+
getContext: ( type ) => ( type === 'webgpu' ? context : null ),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const context = new HeadlessGPUContext( canvas );
|
|
102
|
+
return canvas;
|
|
103
|
+
|
|
104
|
+
}
|
|
@@ -12,7 +12,9 @@ async function getInitUNetFromBuffer() {
|
|
|
12
12
|
|
|
13
13
|
if ( ! _initUNetFromBuffer ) {
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
// The bundle, not the package main: that is raw tsc output with extensionless imports,
|
|
16
|
+
// which Node's ESM resolver refuses.
|
|
17
|
+
_initUNetFromBuffer = ( await import( 'oidn-web/dist/oidn.js' ) ).initUNetFromBuffer;
|
|
16
18
|
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -365,7 +367,7 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
365
367
|
|
|
366
368
|
}
|
|
367
369
|
|
|
368
|
-
|
|
370
|
+
_setupUNetDenoiser() {
|
|
369
371
|
|
|
370
372
|
if ( this.state.isLoading ) {
|
|
371
373
|
|
|
@@ -373,10 +375,24 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
373
375
|
// nothing would ever fetch them. Reachable on every render now that the refreshes and
|
|
374
376
|
// the finished image use different tiers. Flag it; the running load picks it up.
|
|
375
377
|
this._reloadPending = true;
|
|
376
|
-
return;
|
|
378
|
+
return Promise.resolve();
|
|
377
379
|
|
|
378
380
|
}
|
|
379
381
|
|
|
382
|
+
this._loading = this._loadUNet();
|
|
383
|
+
return this._loading;
|
|
384
|
+
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** Resolves once no weights are loading, including a reload queued behind the current one. */
|
|
388
|
+
whenLoaded() {
|
|
389
|
+
|
|
390
|
+
return this.state.isLoading ? this._loading : Promise.resolve();
|
|
391
|
+
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
async _loadUNet() {
|
|
395
|
+
|
|
380
396
|
do {
|
|
381
397
|
|
|
382
398
|
this._reloadPending = false;
|
|
@@ -389,7 +405,7 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
389
405
|
} catch ( error ) {
|
|
390
406
|
|
|
391
407
|
log.error( 'UNet weights failed to load:', error );
|
|
392
|
-
this.dispatchEvent( { type: 'error', error: new Error( `Denoiser loading failed: ${error.message}` ) } );
|
|
408
|
+
this.dispatchEvent( { type: 'error', error: new Error( `Denoiser loading failed: ${error.message}` ), url: this._generateTzaUrl() } );
|
|
393
409
|
|
|
394
410
|
} finally {
|
|
395
411
|
|
|
@@ -973,6 +989,15 @@ export class OIDNDenoiser extends EventDispatcher {
|
|
|
973
989
|
|
|
974
990
|
}
|
|
975
991
|
|
|
992
|
+
/** Bytes of the GPU memory this pass allocates itself; oidn-web's network is not among them. */
|
|
993
|
+
gpuBytes() {
|
|
994
|
+
|
|
995
|
+
const { color, albedo, normal } = this._gpuInputBuffers;
|
|
996
|
+
const out = this._outGPUTexture ? this._outTexSize.width * this._outTexSize.height * 8 : 0; // rgba16float
|
|
997
|
+
return ( color?.size ?? 0 ) + ( albedo?.size ?? 0 ) + ( normal?.size ?? 0 ) + ( this._gpuInputPadBuffer?.size ?? 0 ) + out;
|
|
998
|
+
|
|
999
|
+
}
|
|
1000
|
+
|
|
976
1001
|
/**
|
|
977
1002
|
* Makes sure the output picture exists at the render size. A resize makes a new one rather than
|
|
978
1003
|
* resizing in place: three.js caches the card-side handle against the wrapper, so the wrapper
|
|
@@ -423,6 +423,13 @@ export class OIDNTemporalHistory {
|
|
|
423
423
|
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
+
gpuBytes() {
|
|
427
|
+
|
|
428
|
+
if ( ! this._sets ) return 0;
|
|
429
|
+
return this._sets.length * 3 * this.width * this.height * 16 + this._picked.size + this._copies.size;
|
|
430
|
+
|
|
431
|
+
}
|
|
432
|
+
|
|
426
433
|
_ensure( width, height ) {
|
|
427
434
|
|
|
428
435
|
if ( ! width || ! height ) return false;
|