rayzee 8.4.1 → 8.6.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 +61 -9
- package/dist/{DLSSNeural-BNSJ8V3z.js → DLSSNeural-BhBCBgKf.js} +5 -5
- package/dist/{DLSSSuperRes-BoEW89Cl.js → DLSSSuperRes-BCA7F_k5.js} +5 -5
- package/dist/ToneMapGPU-BzcLheoR.js +533 -0
- package/dist/rayzee.es.js +27278 -9133
- package/dist/rayzee.umd.js +255 -187
- package/package.json +1 -1
- package/src/AssetConfig.js +15 -2
- package/src/Color/BakedViews.js +134 -0
- package/src/Color/BuiltinViews.js +261 -0
- package/src/Color/ColorManagement.js +1130 -0
- package/src/Color/ColorSpaces.js +432 -0
- package/src/Color/Displays.js +19 -0
- package/src/Color/InputColorSpaces.js +243 -0
- package/src/Color/LutBake.js +371 -0
- package/src/Color/OcioRuntime.js +338 -0
- package/src/Color/OcioViews.js +419 -0
- package/src/Color/ViewTransforms.js +323 -0
- package/src/Color/WorkingMatrix.js +86 -0
- package/src/EngineDefaults.js +84 -4
- package/src/EngineIssues.js +3 -1
- package/src/Passes/AIUpscaler.js +16 -7
- package/src/PathTracerApp.js +318 -35
- package/src/Processor/AssetLoader.js +47 -55
- package/src/Processor/CameraOptimizer.js +22 -6
- package/src/Processor/EmissiveTriangleBuilder.js +34 -2
- package/src/Processor/GeometryExtractor.js +151 -138
- package/src/Processor/LightSerializer.js +17 -20
- package/src/Processor/MaterialPacking.js +168 -0
- package/src/Processor/PackedRayBuffer.js +6 -2
- package/src/Processor/ProceduralSky.js +4 -0
- package/src/Processor/SceneProcessor.js +25 -1
- package/src/Processor/SimpleSky.js +8 -0
- package/src/Processor/TextureCreator.js +137 -91
- package/src/Processor/TextureReadback.js +92 -0
- package/src/Processor/ToneMapCPU.js +80 -165
- package/src/Processor/ToneMapGPU.js +122 -151
- package/src/RenderSettings.js +10 -1
- package/src/Stages/Compositor.js +11 -2
- package/src/Stages/PathTracer.js +21 -4
- package/src/Stages/PathTracerStage.js +11 -18
- package/src/TSL/Common.js +15 -0
- package/src/TSL/Debugger.js +2 -3
- package/src/TSL/EmissiveSampling.js +6 -8
- package/src/TSL/ExtendKernel.js +9 -0
- package/src/TSL/Fresnel.js +23 -1
- package/src/TSL/HitFacet.js +102 -0
- package/src/TSL/LightsDirect.js +12 -33
- package/src/TSL/LightsSampling.js +15 -7
- package/src/TSL/MaterialEvaluation.js +26 -19
- package/src/TSL/MaterialProperties.js +74 -37
- package/src/TSL/MaterialTransmission.js +2 -3
- package/src/TSL/ShadeKernel.js +34 -21
- package/src/TSL/ShadowTerminator.js +125 -0
- package/src/TSL/Struct.js +9 -0
- package/src/TSL/Subsurface.js +2 -3
- package/src/index.js +29 -2
- package/src/managers/DenoisingManager.js +3 -7
- package/src/managers/EnvironmentManager.js +20 -0
- package/src/managers/LightManager.js +17 -15
- package/src/managers/MaterialDataManager.js +118 -208
- package/src/managers/UniformManager.js +1 -0
- package/src/managers/VideoRenderManager.js +9 -9
- package/dist/ToneMapGPU-DzqSyzTx.js +0 -341
- package/src/LightUnits.js +0 -122
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
import { ACESFilmicToneMapping as e, AgXToneMapping as t, CineonToneMapping as n, LinearToneMapping as r, NeutralToneMapping as i, NoToneMapping as a, ReinhardToneMapping as o } from "three";
|
|
2
|
-
//#region src/utils/Logger.js
|
|
3
|
-
var s = {
|
|
4
|
-
silent: 0,
|
|
5
|
-
error: 1,
|
|
6
|
-
warn: 2,
|
|
7
|
-
info: 3,
|
|
8
|
-
debug: 4
|
|
9
|
-
}, c = "info", l = "rayzeeLogLevel", u = "rayzeeLogNamespaces", d = "color:#7c8494", f = "color:inherit", p = null, m = null;
|
|
10
|
-
function h(e) {
|
|
11
|
-
try {
|
|
12
|
-
return globalThis.localStorage?.getItem(e) ?? null;
|
|
13
|
-
} catch {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function g(e, t) {
|
|
18
|
-
try {
|
|
19
|
-
t === null ? globalThis.localStorage?.removeItem(e) : globalThis.localStorage?.setItem(e, t);
|
|
20
|
-
} catch {}
|
|
21
|
-
}
|
|
22
|
-
function _() {
|
|
23
|
-
if (p !== null) return p;
|
|
24
|
-
let e = globalThis.__RAYZEE_LOG_LEVEL__;
|
|
25
|
-
return e !== void 0 && e in s ? (p = s[e], p) : (p = s[h(l)] ?? s[c], p);
|
|
26
|
-
}
|
|
27
|
-
function v() {
|
|
28
|
-
if (m !== null) return m;
|
|
29
|
-
let e = globalThis.__RAYZEE_LOG_NS__ ?? h(u);
|
|
30
|
-
return m = e ? String(e).split(",").map((e) => e.trim()).filter(Boolean) : [], m;
|
|
31
|
-
}
|
|
32
|
-
function y(e, t) {
|
|
33
|
-
if (t < s.debug) return !0;
|
|
34
|
-
let n = v();
|
|
35
|
-
return n.length === 0 || n.some((t) => e === t || e.startsWith(`${t}:`));
|
|
36
|
-
}
|
|
37
|
-
function b(e, t, n) {
|
|
38
|
-
if (e > _() || !y(t, e)) return;
|
|
39
|
-
let r = e === s.error ? console.error : e === s.warn ? console.warn : console.log, i = `[${t}]`;
|
|
40
|
-
typeof n[0] == "string" ? r(`%c${i}%c ${n[0]}`, d, f, ...n.slice(1)) : r(`%c${i}`, d, ...n);
|
|
41
|
-
}
|
|
42
|
-
var x = {
|
|
43
|
-
n: (e) => Number(e).toLocaleString("en-US"),
|
|
44
|
-
ms: (e) => e < 10 ? `${Number(e).toFixed(1)} ms` : `${Math.round(e)} ms`,
|
|
45
|
-
mb: (e) => {
|
|
46
|
-
let t = e / (1024 * 1024);
|
|
47
|
-
return t < 10 ? `${t.toFixed(1)} MB` : `${Math.round(t)} MB`;
|
|
48
|
-
},
|
|
49
|
-
px: (e, t) => `${e}×${t}`,
|
|
50
|
-
count: (e, t, n = `${t}s`) => `${x.n(e)} ${Number(e) === 1 ? t : n}`,
|
|
51
|
-
list: (e) => e.filter(Boolean).join(" · ")
|
|
52
|
-
}, S = {
|
|
53
|
-
levels: s,
|
|
54
|
-
setLevel(e) {
|
|
55
|
-
return e in s ? (globalThis.__RAYZEE_LOG_LEVEL__ = e, p = s[e], g(l, e === c ? null : e), e) : (console.warn(`[log] unknown level '${e}' — expected one of ${Object.keys(s).join(", ")}`), this.getLevel());
|
|
56
|
-
},
|
|
57
|
-
getLevel() {
|
|
58
|
-
let e = _();
|
|
59
|
-
return Object.keys(s).find((t) => s[t] === e);
|
|
60
|
-
},
|
|
61
|
-
isEnabled(e) {
|
|
62
|
-
return (s[e] ?? s.debug) <= _();
|
|
63
|
-
},
|
|
64
|
-
only(...e) {
|
|
65
|
-
let t = e.flat().filter(Boolean);
|
|
66
|
-
return m = t, globalThis.__RAYZEE_LOG_NS__ = t.join(","), g(u, t.length ? t.join(",") : null), t.length && this.setLevel("debug"), t;
|
|
67
|
-
},
|
|
68
|
-
refresh() {
|
|
69
|
-
return p = null, m = null, this.getLevel();
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
function C(e) {
|
|
73
|
-
return {
|
|
74
|
-
namespace: e,
|
|
75
|
-
error: (...t) => b(s.error, e, t),
|
|
76
|
-
warn: (...t) => b(s.warn, e, t),
|
|
77
|
-
info: (...t) => b(s.info, e, t),
|
|
78
|
-
debug: (...t) => b(s.debug, e, t),
|
|
79
|
-
isEnabled: (e) => S.isEnabled(e),
|
|
80
|
-
summary(t, n = []) {
|
|
81
|
-
let r = n.filter(Boolean);
|
|
82
|
-
if (r.length === 0 || !console.groupCollapsed) {
|
|
83
|
-
b(s.info, e, [t]), r.forEach((t) => b(s.debug, e, [t]));
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
s.info > _() || ((_() >= s.debug && console.group ? console.group : console.groupCollapsed)(`%c[${e}]%c ${t}`, d, f), r.forEach((e) => console.log(e)), console.groupEnd());
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
var w = /* @__PURE__ */ new Set();
|
|
91
|
-
function T(e, t, ...n) {
|
|
92
|
-
w.has(t) || (w.add(t), e.warn(...n));
|
|
93
|
-
}
|
|
94
|
-
function E() {
|
|
95
|
-
return S.getLevel();
|
|
96
|
-
}
|
|
97
|
-
//#endregion
|
|
98
|
-
//#region src/AssetConfig.js
|
|
99
|
-
var D = {
|
|
100
|
-
stbnScalarAtlas: "https://assets.rayzee.atulmourya.com/noise/stbn_scalar_atlas.png",
|
|
101
|
-
stbnVec2Atlas: "https://assets.rayzee.atulmourya.com/noise/stbn_vec2_atlas.png",
|
|
102
|
-
ortRuntimeUrl: "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/ort.webgpu.bundle.min.mjs",
|
|
103
|
-
ortWasmPaths: "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.24.3/dist/",
|
|
104
|
-
dracoDecoderPath: "https://www.gstatic.com/draco/v1/decoders/",
|
|
105
|
-
ktx2TranscoderPath: "https://cdn.jsdelivr.net/npm/three@0.183.2/examples/jsm/libs/basis/",
|
|
106
|
-
oidnWeightsBaseUrl: "https://cdn.jsdelivr.net/npm/denoiser/tzas/",
|
|
107
|
-
upscalerModelBaseUrl: "https://huggingface.co/notaneimu/onnx-image-models/resolve/main/",
|
|
108
|
-
dlssRuntimeUrl: "/dlss/dlss-runtime.js",
|
|
109
|
-
dlssAssetBaseUrl: "https://pub-6e048ff014374f11bef33d76b6c2b5ef.r2.dev/v1",
|
|
110
|
-
cacheNamespace: "rayzee"
|
|
111
|
-
};
|
|
112
|
-
function O(e) {
|
|
113
|
-
e && Object.assign(D, e);
|
|
114
|
-
}
|
|
115
|
-
function k() {
|
|
116
|
-
return { ...D };
|
|
117
|
-
}
|
|
118
|
-
var A = `
|
|
119
|
-
struct Params {
|
|
120
|
-
width: u32,
|
|
121
|
-
height: u32,
|
|
122
|
-
mode: u32,
|
|
123
|
-
flipY: u32,
|
|
124
|
-
exposure: f32,
|
|
125
|
-
saturation: f32,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
@group(0) @binding(0) var<storage, read> src: array<u32>;
|
|
129
|
-
@group(0) @binding(1) var<storage, read_write> dst: array<u32>;
|
|
130
|
-
@group(0) @binding(2) var<uniform> params: Params;
|
|
131
|
-
|
|
132
|
-
${`
|
|
133
|
-
const TM_NONE: u32 = ${a}u;
|
|
134
|
-
const TM_LINEAR: u32 = ${r}u;
|
|
135
|
-
const TM_REINHARD: u32 = ${o}u;
|
|
136
|
-
const TM_CINEON: u32 = ${n}u;
|
|
137
|
-
const TM_ACES: u32 = ${e}u;
|
|
138
|
-
const TM_AGX: u32 = ${t}u;
|
|
139
|
-
const TM_NEUTRAL: u32 = ${i}u;
|
|
140
|
-
|
|
141
|
-
fn tm_reinhard( c: vec3<f32> ) -> vec3<f32> {
|
|
142
|
-
return clamp( c / ( c + vec3<f32>( 1.0 ) ), vec3<f32>( 0.0 ), vec3<f32>( 1.0 ) );
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
fn tm_cineon( c0: vec3<f32> ) -> vec3<f32> {
|
|
146
|
-
let c = max( c0 - vec3<f32>( 0.004 ), vec3<f32>( 0.0 ) );
|
|
147
|
-
let v = ( c * ( 6.2 * c + vec3<f32>( 0.5 ) ) ) / ( c * ( 6.2 * c + vec3<f32>( 1.7 ) ) + vec3<f32>( 0.06 ) );
|
|
148
|
-
return pow( max( v, vec3<f32>( 0.0 ) ), vec3<f32>( 2.2 ) );
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
fn tm_aces( c0: vec3<f32> ) -> vec3<f32> {
|
|
152
|
-
let c = c0 / 0.6;
|
|
153
|
-
let m_in = mat3x3<f32>(
|
|
154
|
-
vec3<f32>( 0.59719, 0.07600, 0.02840 ),
|
|
155
|
-
vec3<f32>( 0.35458, 0.90834, 0.13383 ),
|
|
156
|
-
vec3<f32>( 0.04823, 0.01566, 0.83777 ) );
|
|
157
|
-
let v = m_in * c;
|
|
158
|
-
let a = v * ( v + vec3<f32>( 0.0245786 ) ) - vec3<f32>( 0.000090537 );
|
|
159
|
-
let b = v * ( 0.983729 * v + vec3<f32>( 0.4329510 ) ) + vec3<f32>( 0.238081 );
|
|
160
|
-
let m_out = mat3x3<f32>(
|
|
161
|
-
vec3<f32>( 1.60475, -0.10208, -0.00327 ),
|
|
162
|
-
vec3<f32>( -0.53108, 1.10813, -0.07276 ),
|
|
163
|
-
vec3<f32>( -0.07367, -0.00605, 1.07602 ) );
|
|
164
|
-
return clamp( m_out * ( a / b ), vec3<f32>( 0.0 ), vec3<f32>( 1.0 ) );
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
fn tm_agx( c0: vec3<f32> ) -> vec3<f32> {
|
|
168
|
-
let m_in = mat3x3<f32>(
|
|
169
|
-
vec3<f32>( 0.6274, 0.0691, 0.0164 ),
|
|
170
|
-
vec3<f32>( 0.3293, 0.9195, 0.0880 ),
|
|
171
|
-
vec3<f32>( 0.0433, 0.0113, 0.8956 ) );
|
|
172
|
-
let m_agx = mat3x3<f32>(
|
|
173
|
-
vec3<f32>( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),
|
|
174
|
-
vec3<f32>( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),
|
|
175
|
-
vec3<f32>( 0.0482516061458583, 0.101439036467562, 0.811302368396859 ) );
|
|
176
|
-
|
|
177
|
-
var v = m_agx * ( m_in * c0 );
|
|
178
|
-
|
|
179
|
-
let minEv = -12.47393;
|
|
180
|
-
let maxEv = 4.026069;
|
|
181
|
-
v = clamp( ( log2( max( v, vec3<f32>( 1e-10 ) ) ) - vec3<f32>( minEv ) ) / ( maxEv - minEv ),
|
|
182
|
-
vec3<f32>( 0.0 ), vec3<f32>( 1.0 ) );
|
|
183
|
-
|
|
184
|
-
let x2 = v * v;
|
|
185
|
-
let x4 = x2 * x2;
|
|
186
|
-
v = 15.5 * x4 * x2 - 40.14 * x4 * v + 31.96 * x4 - 6.868 * x2 * v + 0.4298 * x2 + 0.1191 * v
|
|
187
|
-
- vec3<f32>( 0.00232 );
|
|
188
|
-
|
|
189
|
-
let m_out = mat3x3<f32>(
|
|
190
|
-
vec3<f32>( 1.1271005818144368, -0.1413297634984383, -0.14132976349843826 ),
|
|
191
|
-
vec3<f32>( -0.11060664309660323, 1.157823702216272, -0.11060664309660294 ),
|
|
192
|
-
vec3<f32>( -0.016493938717834573, -0.016493938717834257, 1.2519364065950405 ) );
|
|
193
|
-
let o = pow( max( m_out * v, vec3<f32>( 0.0 ) ), vec3<f32>( 2.2 ) );
|
|
194
|
-
|
|
195
|
-
let m_srgb = mat3x3<f32>(
|
|
196
|
-
vec3<f32>( 1.6605, -0.1246, -0.0182 ),
|
|
197
|
-
vec3<f32>( -0.5876, 1.1329, -0.1006 ),
|
|
198
|
-
vec3<f32>( -0.0728, -0.0083, 1.1187 ) );
|
|
199
|
-
return clamp( m_srgb * o, vec3<f32>( 0.0 ), vec3<f32>( 1.0 ) );
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
fn tm_neutral( c0: vec3<f32> ) -> vec3<f32> {
|
|
203
|
-
let startCompression = 0.8 - 0.04;
|
|
204
|
-
let desaturation = 0.15;
|
|
205
|
-
|
|
206
|
-
let x = min( c0.r, min( c0.g, c0.b ) );
|
|
207
|
-
var offset = 0.04;
|
|
208
|
-
if ( x < 0.08 ) { offset = x - 6.25 * x * x; }
|
|
209
|
-
var c = c0 - vec3<f32>( offset );
|
|
210
|
-
|
|
211
|
-
let peak = max( c.r, max( c.g, c.b ) );
|
|
212
|
-
if ( peak < startCompression ) { return c; }
|
|
213
|
-
|
|
214
|
-
let d = 1.0 - startCompression;
|
|
215
|
-
let newPeak = 1.0 - d * d / ( peak + d - startCompression );
|
|
216
|
-
c = c * ( newPeak / peak );
|
|
217
|
-
let gFactor = 1.0 - 1.0 / ( desaturation * ( peak - newPeak ) + 1.0 );
|
|
218
|
-
return mix( c, vec3<f32>( newPeak ), gFactor );
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Three.js clamps the fragment output with max(0) before tone mapping, so the curves never see a
|
|
222
|
-
// negative channel. The saturation grade drives channels below zero on much of a typical frame, and
|
|
223
|
-
// AgX/Neutral mix negatives across channels instead of clipping them.
|
|
224
|
-
fn rayzee_tone_curve( color: vec3<f32>, mode: u32 ) -> vec3<f32> {
|
|
225
|
-
let c = max( color, vec3<f32>( 0.0 ) );
|
|
226
|
-
if ( mode == TM_REINHARD ) { return tm_reinhard( c ); }
|
|
227
|
-
if ( mode == TM_CINEON ) { return tm_cineon( c ); }
|
|
228
|
-
if ( mode == TM_ACES ) { return tm_aces( c ); }
|
|
229
|
-
if ( mode == TM_AGX ) { return tm_agx( c ); }
|
|
230
|
-
if ( mode == TM_NEUTRAL ) { return tm_neutral( c ); }
|
|
231
|
-
return clamp( c, vec3<f32>( 0.0 ), vec3<f32>( 1.0 ) );
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
fn rayzee_tone_map( linearRGB: vec3<f32>, mode: u32, exposure: f32, saturation: f32 ) -> vec3<f32> {
|
|
235
|
-
// Three.js returns early for NoToneMapping without applying exposure, so a readback that applied
|
|
236
|
-
// it would paint brighter than the viewport it replaces.
|
|
237
|
-
var c = linearRGB * select( exposure, 1.0, mode == TM_NONE );
|
|
238
|
-
if ( saturation != 1.0 ) {
|
|
239
|
-
let luma = vec3<f32>( dot( c, vec3<f32>( 0.2126, 0.7152, 0.0722 ) ) );
|
|
240
|
-
c = luma + ( c - luma ) * saturation;
|
|
241
|
-
}
|
|
242
|
-
return rayzee_tone_curve( c, mode );
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
fn rayzee_linear_to_srgb( c: vec3<f32> ) -> vec3<f32> {
|
|
246
|
-
return select(
|
|
247
|
-
1.055 * pow( max( c, vec3<f32>( 0.0 ) ), vec3<f32>( 1.0 / 2.4 ) ) - vec3<f32>( 0.055 ),
|
|
248
|
-
12.92 * c,
|
|
249
|
-
c <= vec3<f32>( 0.0031308 ) );
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
fn rayzee_to_u8( srgb: vec3<f32> ) -> vec3<u32> {
|
|
253
|
-
return vec3<u32>( clamp( round( srgb * 255.0 + vec3<f32>( 0.5 ) ), vec3<f32>( 0.0 ), vec3<f32>( 255.0 ) ) );
|
|
254
|
-
}
|
|
255
|
-
`}
|
|
256
|
-
|
|
257
|
-
@compute @workgroup_size(8, 8)
|
|
258
|
-
fn main( @builtin(global_invocation_id) gid: vec3<u32> ) {
|
|
259
|
-
if ( gid.x >= params.width || gid.y >= params.height ) { return; }
|
|
260
|
-
|
|
261
|
-
var srcY = gid.y;
|
|
262
|
-
if ( params.flipY == 1u ) { srcY = params.height - 1u - gid.y; }
|
|
263
|
-
|
|
264
|
-
let a = ( srcY * params.width + gid.x ) * 2u;
|
|
265
|
-
let rg = unpack2x16float( src[ a ] );
|
|
266
|
-
let ba = unpack2x16float( src[ a + 1u ] );
|
|
267
|
-
|
|
268
|
-
let mapped = rayzee_tone_map( vec3<f32>( rg.x, rg.y, ba.x ), params.mode, params.exposure, params.saturation );
|
|
269
|
-
let b8 = rayzee_to_u8( rayzee_linear_to_srgb( mapped ) );
|
|
270
|
-
dst[ gid.y * params.width + gid.x ] = b8.x | ( b8.y << 8u ) | ( b8.z << 16u ) | ( 255u << 24u );
|
|
271
|
-
}
|
|
272
|
-
`, j = 32, M = class {
|
|
273
|
-
constructor(e, t = "rayzee:tonemap") {
|
|
274
|
-
this.device = e, this.label = t, this.width = 0, this.height = 0, this._pipeline = null, this._storage = null, this._map = null, this._params = null, this._paramData = new ArrayBuffer(j), this._paramU32 = new Uint32Array(this._paramData), this._paramF32 = new Float32Array(this._paramData), this.disposed = !1;
|
|
275
|
-
}
|
|
276
|
-
ensureSize(e, t) {
|
|
277
|
-
if (this.width === e && this.height === t && this._pipeline) return;
|
|
278
|
-
this._releaseBuffers();
|
|
279
|
-
let n = e * t * 4;
|
|
280
|
-
this._storage = this.device.createBuffer({
|
|
281
|
-
label: `${this.label}-out`,
|
|
282
|
-
size: n,
|
|
283
|
-
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
|
|
284
|
-
}), this._map = this.device.createBuffer({
|
|
285
|
-
label: `${this.label}-map`,
|
|
286
|
-
size: n,
|
|
287
|
-
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
288
|
-
}), this._params = this.device.createBuffer({
|
|
289
|
-
label: `${this.label}-params`,
|
|
290
|
-
size: j,
|
|
291
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
292
|
-
}), this._pipeline ??= this.device.createComputePipeline({
|
|
293
|
-
label: this.label,
|
|
294
|
-
layout: "auto",
|
|
295
|
-
compute: {
|
|
296
|
-
module: this.device.createShaderModule({
|
|
297
|
-
label: this.label,
|
|
298
|
-
code: A
|
|
299
|
-
}),
|
|
300
|
-
entryPoint: "main"
|
|
301
|
-
}
|
|
302
|
-
}), this.width = e, this.height = t;
|
|
303
|
-
}
|
|
304
|
-
async toRGBA8(e, { exposure: t = 1, toneMapping: n = 0, saturation: r = 1, flipY: i = !1 } = {}) {
|
|
305
|
-
if (this.disposed) throw Error("PackedToneMapper: disposed");
|
|
306
|
-
if (!this._pipeline) throw Error("PackedToneMapper: call ensureSize() first");
|
|
307
|
-
let { width: a, height: o } = this;
|
|
308
|
-
this._paramU32[0] = a, this._paramU32[1] = o, this._paramU32[2] = n >>> 0, this._paramU32[3] = +!!i, this._paramF32[4] = t, this._paramF32[5] = r, this.device.queue.writeBuffer(this._params, 0, this._paramData);
|
|
309
|
-
let s = this.device.createBindGroup({
|
|
310
|
-
layout: this._pipeline.getBindGroupLayout(0),
|
|
311
|
-
entries: [
|
|
312
|
-
{
|
|
313
|
-
binding: 0,
|
|
314
|
-
resource: {
|
|
315
|
-
buffer: e,
|
|
316
|
-
size: a * o * 8
|
|
317
|
-
}
|
|
318
|
-
},
|
|
319
|
-
{
|
|
320
|
-
binding: 1,
|
|
321
|
-
resource: { buffer: this._storage }
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
binding: 2,
|
|
325
|
-
resource: { buffer: this._params }
|
|
326
|
-
}
|
|
327
|
-
]
|
|
328
|
-
}), c = this.device.createCommandEncoder({ label: this.label }), l = c.beginComputePass();
|
|
329
|
-
l.setPipeline(this._pipeline), l.setBindGroup(0, s), l.dispatchWorkgroups(Math.ceil(a / 8), Math.ceil(o / 8)), l.end(), c.copyBufferToBuffer(this._storage, 0, this._map, 0, a * o * 4), this.device.queue.submit([c.finish()]), await this._map.mapAsync(GPUMapMode.READ);
|
|
330
|
-
let u = new Uint8ClampedArray(this._map.getMappedRange().slice(0));
|
|
331
|
-
return this._map.unmap(), u;
|
|
332
|
-
}
|
|
333
|
-
_releaseBuffers() {
|
|
334
|
-
this._storage?.destroy(), this._map?.destroy(), this._params?.destroy(), this._storage = null, this._map = null, this._params = null;
|
|
335
|
-
}
|
|
336
|
-
dispose() {
|
|
337
|
-
this.disposed || (this.disposed = !0, this._releaseBuffers(), this._pipeline = null);
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
//#endregion
|
|
341
|
-
export { S as a, T as c, s as i, E as l, O as n, C as o, k as r, x as s, M as t };
|
package/src/LightUnits.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The engine's light-unit rule, stated once.
|
|
3
|
-
*
|
|
4
|
-
* Every light in the scene graph is a **valid three.js light**: it carries the quantity three.js
|
|
5
|
-
* expects for its type, measured in radiometric (watt-based) units rather than photometric ones.
|
|
6
|
-
*
|
|
7
|
-
* point / spot → radiant intensity W/sr
|
|
8
|
-
* directional → irradiance W/m²
|
|
9
|
-
* rect area → radiance W/(sr·m²), `width`/`height` in world metres, unit scale
|
|
10
|
-
*
|
|
11
|
-
* three.js' shading maths is unit-agnostic — it divides by distance² and integrates a form factor,
|
|
12
|
-
* never caring whether the number it was handed is candela or W/sr. Feeding it radiometric values
|
|
13
|
-
* therefore makes the raster fallback, the light helpers and any host reading `sceneModel` correct
|
|
14
|
-
* without one of them knowing anything about the path tracer.
|
|
15
|
-
*
|
|
16
|
-
* Blender-style **Power in Watts** — what the Lights panel edits — is a view of that, converted
|
|
17
|
-
* here and nowhere else. `LightSerializer` converts the other way when it fills the GPU buffer.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/** Luminous efficacy that glTF, three.js and Blender's exporter all assume (lm/W). */
|
|
21
|
-
export const LUMENS_PER_WATT = 683;
|
|
22
|
-
|
|
23
|
-
/** Emitting area in m², including the ellipse/disk shape factor. Assumes unit world scale. */
|
|
24
|
-
export function areaLightArea( light ) {
|
|
25
|
-
|
|
26
|
-
const shape = light.userData?.shape;
|
|
27
|
-
const shapeFactor = shape === 'ellipse' || shape === 'disk' ? Math.PI / 4 : 1;
|
|
28
|
-
const area = Math.abs( light.width * light.height ) * shapeFactor;
|
|
29
|
-
return Number.isFinite( area ) && area > 0 ? area : 0;
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Blender-style Power for the Lights panel: radiant power in W for point, spot and area lights,
|
|
35
|
-
* and the Sun's strength in W/m² unchanged.
|
|
36
|
-
*/
|
|
37
|
-
export function lightPower( light ) {
|
|
38
|
-
|
|
39
|
-
if ( light.isRectAreaLight ) {
|
|
40
|
-
|
|
41
|
-
const normalize = light.userData?.normalize ?? true;
|
|
42
|
-
return light.intensity * Math.PI * ( normalize ? areaLightArea( light ) : 1 );
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if ( light.isPointLight || light.isSpotLight ) return light.intensity * 4 * Math.PI;
|
|
47
|
-
|
|
48
|
-
return light.intensity;
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Inverse of {@link lightPower} — what the panel writes back. */
|
|
53
|
-
export function setLightPower( light, watts ) {
|
|
54
|
-
|
|
55
|
-
if ( light.isRectAreaLight ) {
|
|
56
|
-
|
|
57
|
-
const normalize = light.userData?.normalize ?? true;
|
|
58
|
-
const denominator = Math.PI * ( normalize ? areaLightArea( light ) : 1 );
|
|
59
|
-
light.intensity = denominator > 0 ? watts / denominator : 0;
|
|
60
|
-
return;
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if ( light.isPointLight || light.isSpotLight ) {
|
|
65
|
-
|
|
66
|
-
light.intensity = watts / ( 4 * Math.PI );
|
|
67
|
-
return;
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
light.intensity = watts;
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Runs `mutate` with the light's Power held constant.
|
|
77
|
-
*
|
|
78
|
-
* Resizing a normalized area light is meant to keep its total power and change its radiance —
|
|
79
|
-
* Blender's Normalize toggle. Since the stored quantity is radiance, that only happens if the
|
|
80
|
-
* edit puts the Power back afterwards. With Normalize off, Power does not depend on the area,
|
|
81
|
-
* so this is a no-op and the same call is still correct.
|
|
82
|
-
*/
|
|
83
|
-
export function preserveLightPower( light, mutate ) {
|
|
84
|
-
|
|
85
|
-
const watts = lightPower( light );
|
|
86
|
-
mutate();
|
|
87
|
-
setLightPower( light, watts );
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Puts an area light's rectangle in world metres with unit scale, leaving its world size and
|
|
93
|
-
* placement untouched.
|
|
94
|
-
*
|
|
95
|
-
* ⚠️ three.js' rasteriser reads `width`/`height` as WORLD dimensions and drops any scale inherited
|
|
96
|
-
* from parent nodes — `RectAreaLightNode` builds the light's basis with `extractRotation`, which
|
|
97
|
-
* normalises the scale away. A light authored as 70 units under a 0.01 node scale therefore rasters
|
|
98
|
-
* as a **70 metre** panel while the path tracer, which uses the world matrix, renders the 0.7 m one
|
|
99
|
-
* it should. Measured on 24001884.glb: 58.7x too bright in the raster view. Baking the scale in and
|
|
100
|
-
* cancelling it on the light itself makes every reader agree.
|
|
101
|
-
*
|
|
102
|
-
* Idempotent: a light already at unit scale is left alone, so re-processing a tree is safe.
|
|
103
|
-
*/
|
|
104
|
-
export function bakeAreaLightScale( light ) {
|
|
105
|
-
|
|
106
|
-
light.updateWorldMatrix( true, false );
|
|
107
|
-
|
|
108
|
-
// Column lengths of the world matrix, read directly so this module needs no three.js import.
|
|
109
|
-
const e = light.matrixWorld.elements;
|
|
110
|
-
const sx = Math.hypot( e[ 0 ], e[ 1 ], e[ 2 ] );
|
|
111
|
-
const sy = Math.hypot( e[ 4 ], e[ 5 ], e[ 6 ] );
|
|
112
|
-
const sz = Math.hypot( e[ 8 ], e[ 9 ], e[ 10 ] );
|
|
113
|
-
|
|
114
|
-
if ( ! Number.isFinite( sx ) || ! Number.isFinite( sy ) || sx === 0 || sy === 0 ) return;
|
|
115
|
-
if ( Math.abs( sx - 1 ) < 1e-9 && Math.abs( sy - 1 ) < 1e-9 ) return;
|
|
116
|
-
|
|
117
|
-
light.width = Math.abs( light.width * sx );
|
|
118
|
-
light.height = Math.abs( light.height * sy );
|
|
119
|
-
light.scale.set( light.scale.x / sx, light.scale.y / sy, sz === 0 ? light.scale.z : light.scale.z / sz );
|
|
120
|
-
light.updateMatrixWorld( true );
|
|
121
|
-
|
|
122
|
-
}
|