@react-three/fiber 10.0.0-alpha.2 → 10.0.0-canary.b0fafc8
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/LICENSE +21 -21
- package/dist/index.cjs +1122 -558
- package/dist/index.d.cts +2001 -1285
- package/dist/index.d.mts +2001 -1285
- package/dist/index.d.ts +2001 -1285
- package/dist/index.mjs +1107 -562
- package/dist/legacy.cjs +1093 -547
- package/dist/legacy.d.cts +2002 -1286
- package/dist/legacy.d.mts +2002 -1286
- package/dist/legacy.d.ts +2002 -1286
- package/dist/legacy.mjs +1078 -551
- package/dist/webgpu/index.cjs +1176 -548
- package/dist/webgpu/index.d.cts +2097 -1300
- package/dist/webgpu/index.d.mts +2097 -1300
- package/dist/webgpu/index.d.ts +2097 -1300
- package/dist/webgpu/index.mjs +1161 -552
- package/package.json +3 -1
- package/readme.md +244 -318
package/dist/webgpu/index.cjs
CHANGED
|
@@ -6,6 +6,12 @@ const jsxRuntime = require('react/jsx-runtime');
|
|
|
6
6
|
const React = require('react');
|
|
7
7
|
const useMeasure = require('react-use-measure');
|
|
8
8
|
const itsFine = require('its-fine');
|
|
9
|
+
const fiber = require('@react-three/fiber');
|
|
10
|
+
const GroundedSkybox_js = require('three/examples/jsm/objects/GroundedSkybox.js');
|
|
11
|
+
const HDRLoader_js = require('three/examples/jsm/loaders/HDRLoader.js');
|
|
12
|
+
const EXRLoader_js = require('three/examples/jsm/loaders/EXRLoader.js');
|
|
13
|
+
const UltraHDRLoader_js = require('three/examples/jsm/loaders/UltraHDRLoader.js');
|
|
14
|
+
const gainmapJs = require('@monogrid/gainmap-js');
|
|
9
15
|
const Tb = require('scheduler');
|
|
10
16
|
const traditional = require('zustand/traditional');
|
|
11
17
|
const suspendReact = require('suspend-react');
|
|
@@ -67,6 +73,374 @@ const THREE = /*#__PURE__*/_mergeNamespaces({
|
|
|
67
73
|
WebGLRenderer: WebGLRenderer
|
|
68
74
|
}, [webgpu__namespace]);
|
|
69
75
|
|
|
76
|
+
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
77
|
+
const pendingSubscribers = /* @__PURE__ */ new Map();
|
|
78
|
+
function registerPrimary(id, renderer, store) {
|
|
79
|
+
if (primaryRegistry.has(id)) {
|
|
80
|
+
console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
|
|
81
|
+
}
|
|
82
|
+
const entry = { renderer, store };
|
|
83
|
+
primaryRegistry.set(id, entry);
|
|
84
|
+
const subscribers = pendingSubscribers.get(id);
|
|
85
|
+
if (subscribers) {
|
|
86
|
+
subscribers.forEach((callback) => callback(entry));
|
|
87
|
+
pendingSubscribers.delete(id);
|
|
88
|
+
}
|
|
89
|
+
return () => {
|
|
90
|
+
const currentEntry = primaryRegistry.get(id);
|
|
91
|
+
if (currentEntry?.renderer === renderer) {
|
|
92
|
+
primaryRegistry.delete(id);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function getPrimary(id) {
|
|
97
|
+
return primaryRegistry.get(id);
|
|
98
|
+
}
|
|
99
|
+
function waitForPrimary(id, timeout = 5e3) {
|
|
100
|
+
const existing = primaryRegistry.get(id);
|
|
101
|
+
if (existing) {
|
|
102
|
+
return Promise.resolve(existing);
|
|
103
|
+
}
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
const timeoutId = setTimeout(() => {
|
|
106
|
+
const subscribers = pendingSubscribers.get(id);
|
|
107
|
+
if (subscribers) {
|
|
108
|
+
const index = subscribers.indexOf(callback);
|
|
109
|
+
if (index !== -1) subscribers.splice(index, 1);
|
|
110
|
+
if (subscribers.length === 0) pendingSubscribers.delete(id);
|
|
111
|
+
}
|
|
112
|
+
reject(new Error(`Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}"> is mounted.`));
|
|
113
|
+
}, timeout);
|
|
114
|
+
const callback = (entry) => {
|
|
115
|
+
clearTimeout(timeoutId);
|
|
116
|
+
resolve(entry);
|
|
117
|
+
};
|
|
118
|
+
if (!pendingSubscribers.has(id)) {
|
|
119
|
+
pendingSubscribers.set(id, []);
|
|
120
|
+
}
|
|
121
|
+
pendingSubscribers.get(id).push(callback);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function hasPrimary(id) {
|
|
125
|
+
return primaryRegistry.has(id);
|
|
126
|
+
}
|
|
127
|
+
function unregisterPrimary(id) {
|
|
128
|
+
primaryRegistry.delete(id);
|
|
129
|
+
}
|
|
130
|
+
function getPrimaryIds() {
|
|
131
|
+
return Array.from(primaryRegistry.keys());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const presetsObj = {
|
|
135
|
+
apartment: "lebombo_1k.hdr",
|
|
136
|
+
city: "potsdamer_platz_1k.hdr",
|
|
137
|
+
dawn: "kiara_1_dawn_1k.hdr",
|
|
138
|
+
forest: "forest_slope_1k.hdr",
|
|
139
|
+
lobby: "st_fagans_interior_1k.hdr",
|
|
140
|
+
night: "dikhololo_night_1k.hdr",
|
|
141
|
+
park: "rooitou_park_1k.hdr",
|
|
142
|
+
studio: "studio_small_03_1k.hdr",
|
|
143
|
+
sunset: "venice_sunset_1k.hdr",
|
|
144
|
+
warehouse: "empty_warehouse_01_1k.hdr"
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
|
|
148
|
+
const isArray = (arr) => Array.isArray(arr);
|
|
149
|
+
const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
|
|
150
|
+
function useEnvironment({
|
|
151
|
+
files = defaultFiles,
|
|
152
|
+
path = "",
|
|
153
|
+
preset = void 0,
|
|
154
|
+
colorSpace = void 0,
|
|
155
|
+
extensions
|
|
156
|
+
} = {}) {
|
|
157
|
+
if (preset) {
|
|
158
|
+
validatePreset(preset);
|
|
159
|
+
files = presetsObj[preset];
|
|
160
|
+
path = CUBEMAP_ROOT;
|
|
161
|
+
}
|
|
162
|
+
const multiFile = isArray(files);
|
|
163
|
+
const { extension, isCubemap } = getExtension(files);
|
|
164
|
+
const loader = getLoader$1(extension);
|
|
165
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
166
|
+
const renderer = fiber.useThree((state) => state.renderer);
|
|
167
|
+
React.useLayoutEffect(() => {
|
|
168
|
+
if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
|
|
169
|
+
function clearGainmapTexture() {
|
|
170
|
+
fiber.useLoader.clear(loader, multiFile ? [files] : files);
|
|
171
|
+
}
|
|
172
|
+
renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
|
|
173
|
+
}, [files, renderer.domElement]);
|
|
174
|
+
const loaderResult = fiber.useLoader(
|
|
175
|
+
loader,
|
|
176
|
+
multiFile ? [files] : files,
|
|
177
|
+
(loader2) => {
|
|
178
|
+
if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
|
|
179
|
+
loader2.setRenderer?.(renderer);
|
|
180
|
+
}
|
|
181
|
+
loader2.setPath?.(path);
|
|
182
|
+
if (extensions) extensions(loader2);
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
let texture = multiFile ? (
|
|
186
|
+
// @ts-ignore
|
|
187
|
+
loaderResult[0]
|
|
188
|
+
) : loaderResult;
|
|
189
|
+
if (extension === "jpg" || extension === "jpeg" || extension === "webp") {
|
|
190
|
+
texture = texture.renderTarget?.texture;
|
|
191
|
+
}
|
|
192
|
+
texture.mapping = isCubemap ? webgpu.CubeReflectionMapping : webgpu.EquirectangularReflectionMapping;
|
|
193
|
+
texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
|
|
194
|
+
return texture;
|
|
195
|
+
}
|
|
196
|
+
const preloadDefaultOptions = {
|
|
197
|
+
files: defaultFiles,
|
|
198
|
+
path: "",
|
|
199
|
+
preset: void 0,
|
|
200
|
+
extensions: void 0
|
|
201
|
+
};
|
|
202
|
+
useEnvironment.preload = (preloadOptions) => {
|
|
203
|
+
const options = { ...preloadDefaultOptions, ...preloadOptions };
|
|
204
|
+
let { files, path = "" } = options;
|
|
205
|
+
const { preset, extensions } = options;
|
|
206
|
+
if (preset) {
|
|
207
|
+
validatePreset(preset);
|
|
208
|
+
files = presetsObj[preset];
|
|
209
|
+
path = CUBEMAP_ROOT;
|
|
210
|
+
}
|
|
211
|
+
const { extension } = getExtension(files);
|
|
212
|
+
if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
|
|
213
|
+
throw new Error("useEnvironment: Preloading gainmaps is not supported");
|
|
214
|
+
}
|
|
215
|
+
const loader = getLoader$1(extension);
|
|
216
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
217
|
+
fiber.useLoader.preload(loader, isArray(files) ? [files] : files, (loader2) => {
|
|
218
|
+
loader2.setPath?.(path);
|
|
219
|
+
if (extensions) extensions(loader2);
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
const clearDefaultOptins = {
|
|
223
|
+
files: defaultFiles,
|
|
224
|
+
preset: void 0
|
|
225
|
+
};
|
|
226
|
+
useEnvironment.clear = (clearOptions) => {
|
|
227
|
+
const options = { ...clearDefaultOptins, ...clearOptions };
|
|
228
|
+
let { files } = options;
|
|
229
|
+
const { preset } = options;
|
|
230
|
+
if (preset) {
|
|
231
|
+
validatePreset(preset);
|
|
232
|
+
files = presetsObj[preset];
|
|
233
|
+
}
|
|
234
|
+
const { extension } = getExtension(files);
|
|
235
|
+
const loader = getLoader$1(extension);
|
|
236
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
237
|
+
fiber.useLoader.clear(loader, isArray(files) ? [files] : files);
|
|
238
|
+
};
|
|
239
|
+
function validatePreset(preset) {
|
|
240
|
+
if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
|
|
241
|
+
}
|
|
242
|
+
function getExtension(files) {
|
|
243
|
+
const isCubemap = isArray(files) && files.length === 6;
|
|
244
|
+
const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
|
|
245
|
+
const firstEntry = isArray(files) ? files[0] : files;
|
|
246
|
+
const extension = isCubemap ? "cube" : isGainmap ? "webp" : firstEntry.startsWith("data:application/exr") ? "exr" : firstEntry.startsWith("data:application/hdr") ? "hdr" : firstEntry.startsWith("data:image/jpeg") ? "jpg" : firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
|
|
247
|
+
return { extension, isCubemap, isGainmap };
|
|
248
|
+
}
|
|
249
|
+
function getLoader$1(extension) {
|
|
250
|
+
const loader = extension === "cube" ? webgpu.CubeTextureLoader : extension === "hdr" ? HDRLoader_js.HDRLoader : extension === "exr" ? EXRLoader_js.EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader_js.UltraHDRLoader : extension === "webp" ? gainmapJs.GainMapLoader : null;
|
|
251
|
+
return loader;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const isRef$1 = (obj) => obj.current && obj.current.isScene;
|
|
255
|
+
const resolveScene = (scene) => isRef$1(scene) ? scene.current : scene;
|
|
256
|
+
function setEnvProps(background, scene, defaultScene, texture, sceneProps = {}) {
|
|
257
|
+
sceneProps = {
|
|
258
|
+
backgroundBlurriness: 0,
|
|
259
|
+
backgroundIntensity: 1,
|
|
260
|
+
backgroundRotation: [0, 0, 0],
|
|
261
|
+
environmentIntensity: 1,
|
|
262
|
+
environmentRotation: [0, 0, 0],
|
|
263
|
+
...sceneProps
|
|
264
|
+
};
|
|
265
|
+
const target = resolveScene(scene || defaultScene);
|
|
266
|
+
const oldbg = target.background;
|
|
267
|
+
const oldenv = target.environment;
|
|
268
|
+
const oldSceneProps = {
|
|
269
|
+
// @ts-ignore
|
|
270
|
+
backgroundBlurriness: target.backgroundBlurriness,
|
|
271
|
+
// @ts-ignore
|
|
272
|
+
backgroundIntensity: target.backgroundIntensity,
|
|
273
|
+
// @ts-ignore
|
|
274
|
+
backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
|
|
275
|
+
// @ts-ignore
|
|
276
|
+
environmentIntensity: target.environmentIntensity,
|
|
277
|
+
// @ts-ignore
|
|
278
|
+
environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
|
|
279
|
+
};
|
|
280
|
+
if (background !== "only") target.environment = texture;
|
|
281
|
+
if (background) target.background = texture;
|
|
282
|
+
fiber.applyProps(target, sceneProps);
|
|
283
|
+
return () => {
|
|
284
|
+
if (background !== "only") target.environment = oldenv;
|
|
285
|
+
if (background) target.background = oldbg;
|
|
286
|
+
fiber.applyProps(target, oldSceneProps);
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function EnvironmentMap({ scene, background = false, map, ...config }) {
|
|
290
|
+
const defaultScene = fiber.useThree((state) => state.scene);
|
|
291
|
+
React__namespace.useLayoutEffect(() => {
|
|
292
|
+
if (map) return setEnvProps(background, scene, defaultScene, map, config);
|
|
293
|
+
});
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
function EnvironmentCube({
|
|
297
|
+
background = false,
|
|
298
|
+
scene,
|
|
299
|
+
blur,
|
|
300
|
+
backgroundBlurriness,
|
|
301
|
+
backgroundIntensity,
|
|
302
|
+
backgroundRotation,
|
|
303
|
+
environmentIntensity,
|
|
304
|
+
environmentRotation,
|
|
305
|
+
...rest
|
|
306
|
+
}) {
|
|
307
|
+
const texture = useEnvironment(rest);
|
|
308
|
+
const defaultScene = fiber.useThree((state) => state.scene);
|
|
309
|
+
React__namespace.useLayoutEffect(() => {
|
|
310
|
+
return setEnvProps(background, scene, defaultScene, texture, {
|
|
311
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
312
|
+
backgroundIntensity,
|
|
313
|
+
backgroundRotation,
|
|
314
|
+
environmentIntensity,
|
|
315
|
+
environmentRotation
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
React__namespace.useEffect(() => {
|
|
319
|
+
return () => {
|
|
320
|
+
texture.dispose();
|
|
321
|
+
};
|
|
322
|
+
}, [texture]);
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
function EnvironmentPortal({
|
|
326
|
+
children,
|
|
327
|
+
near = 0.1,
|
|
328
|
+
far = 1e3,
|
|
329
|
+
resolution = 256,
|
|
330
|
+
frames = 1,
|
|
331
|
+
map,
|
|
332
|
+
background = false,
|
|
333
|
+
blur,
|
|
334
|
+
backgroundBlurriness,
|
|
335
|
+
backgroundIntensity,
|
|
336
|
+
backgroundRotation,
|
|
337
|
+
environmentIntensity,
|
|
338
|
+
environmentRotation,
|
|
339
|
+
scene,
|
|
340
|
+
files,
|
|
341
|
+
path,
|
|
342
|
+
preset = void 0,
|
|
343
|
+
extensions
|
|
344
|
+
}) {
|
|
345
|
+
const gl = fiber.useThree((state) => state.gl);
|
|
346
|
+
const defaultScene = fiber.useThree((state) => state.scene);
|
|
347
|
+
const camera = React__namespace.useRef(null);
|
|
348
|
+
const [virtualScene] = React__namespace.useState(() => new webgpu.Scene());
|
|
349
|
+
const fbo = React__namespace.useMemo(() => {
|
|
350
|
+
const fbo2 = new webgpu.WebGLCubeRenderTarget(resolution);
|
|
351
|
+
fbo2.texture.type = webgpu.HalfFloatType;
|
|
352
|
+
return fbo2;
|
|
353
|
+
}, [resolution]);
|
|
354
|
+
React__namespace.useEffect(() => {
|
|
355
|
+
return () => {
|
|
356
|
+
fbo.dispose();
|
|
357
|
+
};
|
|
358
|
+
}, [fbo]);
|
|
359
|
+
React__namespace.useLayoutEffect(() => {
|
|
360
|
+
if (frames === 1) {
|
|
361
|
+
const autoClear = gl.autoClear;
|
|
362
|
+
gl.autoClear = true;
|
|
363
|
+
camera.current.update(gl, virtualScene);
|
|
364
|
+
gl.autoClear = autoClear;
|
|
365
|
+
}
|
|
366
|
+
return setEnvProps(background, scene, defaultScene, fbo.texture, {
|
|
367
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
368
|
+
backgroundIntensity,
|
|
369
|
+
backgroundRotation,
|
|
370
|
+
environmentIntensity,
|
|
371
|
+
environmentRotation
|
|
372
|
+
});
|
|
373
|
+
}, [children, virtualScene, fbo.texture, scene, defaultScene, background, frames, gl]);
|
|
374
|
+
let count = 1;
|
|
375
|
+
fiber.useFrame(() => {
|
|
376
|
+
if (frames === Infinity || count < frames) {
|
|
377
|
+
const autoClear = gl.autoClear;
|
|
378
|
+
gl.autoClear = true;
|
|
379
|
+
camera.current.update(gl, virtualScene);
|
|
380
|
+
gl.autoClear = autoClear;
|
|
381
|
+
count++;
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fiber.createPortal(
|
|
385
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
386
|
+
children,
|
|
387
|
+
/* @__PURE__ */ jsxRuntime.jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
|
|
388
|
+
files || preset ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { background: true, map, extensions }) : null
|
|
389
|
+
] }),
|
|
390
|
+
virtualScene
|
|
391
|
+
) });
|
|
392
|
+
}
|
|
393
|
+
function EnvironmentGround(props) {
|
|
394
|
+
const textureDefault = useEnvironment(props);
|
|
395
|
+
const texture = props.map || textureDefault;
|
|
396
|
+
React__namespace.useMemo(() => fiber.extend({ GroundProjectedEnvImpl: GroundedSkybox_js.GroundedSkybox }), []);
|
|
397
|
+
React__namespace.useEffect(() => {
|
|
398
|
+
return () => {
|
|
399
|
+
textureDefault.dispose();
|
|
400
|
+
};
|
|
401
|
+
}, [textureDefault]);
|
|
402
|
+
const height = props.ground?.height ?? 15;
|
|
403
|
+
const radius = props.ground?.radius ?? 60;
|
|
404
|
+
const scale = props.ground?.scale ?? 1e3;
|
|
405
|
+
const args = React__namespace.useMemo(
|
|
406
|
+
() => [texture, height, radius],
|
|
407
|
+
[texture, height, radius]
|
|
408
|
+
);
|
|
409
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
410
|
+
/* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { ...props, map: texture }),
|
|
411
|
+
/* @__PURE__ */ jsxRuntime.jsx("groundProjectedEnvImpl", { args, scale })
|
|
412
|
+
] });
|
|
413
|
+
}
|
|
414
|
+
function EnvironmentColor({ color, scene }) {
|
|
415
|
+
const defaultScene = fiber.useThree((state) => state.scene);
|
|
416
|
+
React__namespace.useLayoutEffect(() => {
|
|
417
|
+
if (color === void 0) return;
|
|
418
|
+
const target = resolveScene(scene || defaultScene);
|
|
419
|
+
const oldBg = target.background;
|
|
420
|
+
target.background = new webgpu.Color(color);
|
|
421
|
+
return () => {
|
|
422
|
+
target.background = oldBg;
|
|
423
|
+
};
|
|
424
|
+
});
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
function EnvironmentDualSource(props) {
|
|
428
|
+
const { backgroundFiles, ...envProps } = props;
|
|
429
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
430
|
+
/* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...envProps, background: false }),
|
|
431
|
+
/* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
|
|
432
|
+
] });
|
|
433
|
+
}
|
|
434
|
+
function Environment(props) {
|
|
435
|
+
if (props.color && !props.files && !props.preset && !props.map) {
|
|
436
|
+
return /* @__PURE__ */ jsxRuntime.jsx(EnvironmentColor, { ...props });
|
|
437
|
+
}
|
|
438
|
+
if (props.backgroundFiles && props.backgroundFiles !== props.files) {
|
|
439
|
+
return /* @__PURE__ */ jsxRuntime.jsx(EnvironmentDualSource, { ...props });
|
|
440
|
+
}
|
|
441
|
+
return props.ground ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentGround, { ...props }) : props.map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { ...props }) : props.children ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentPortal, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props });
|
|
442
|
+
}
|
|
443
|
+
|
|
70
444
|
var __defProp$3 = Object.defineProperty;
|
|
71
445
|
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
72
446
|
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -246,7 +620,8 @@ function prepare(target, root, type, props) {
|
|
|
246
620
|
object,
|
|
247
621
|
eventCount: 0,
|
|
248
622
|
handlers: {},
|
|
249
|
-
isHidden: false
|
|
623
|
+
isHidden: false,
|
|
624
|
+
deferredRefs: []
|
|
250
625
|
};
|
|
251
626
|
if (object) object.__r3f = instance;
|
|
252
627
|
}
|
|
@@ -295,7 +670,7 @@ function createOcclusionObserverNode(store, uniform) {
|
|
|
295
670
|
let occlusionSetupPromise = null;
|
|
296
671
|
function enableOcclusion(store) {
|
|
297
672
|
const state = store.getState();
|
|
298
|
-
const { internal, renderer
|
|
673
|
+
const { internal, renderer } = state;
|
|
299
674
|
if (internal.occlusionEnabled || occlusionSetupPromise) return;
|
|
300
675
|
const hasOcclusionSupport = typeof renderer?.isOccluded === "function";
|
|
301
676
|
if (!hasOcclusionSupport) {
|
|
@@ -458,6 +833,22 @@ function hasVisibilityHandlers(handlers) {
|
|
|
458
833
|
return !!(handlers.onFramed || handlers.onOccluded || handlers.onVisible);
|
|
459
834
|
}
|
|
460
835
|
|
|
836
|
+
const FROM_REF = Symbol.for("@react-three/fiber.fromRef");
|
|
837
|
+
function fromRef(ref) {
|
|
838
|
+
return { [FROM_REF]: ref };
|
|
839
|
+
}
|
|
840
|
+
function isFromRef(value) {
|
|
841
|
+
return value !== null && typeof value === "object" && FROM_REF in value;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const ONCE = Symbol.for("@react-three/fiber.once");
|
|
845
|
+
function once(...args) {
|
|
846
|
+
return { [ONCE]: args.length ? args : true };
|
|
847
|
+
}
|
|
848
|
+
function isOnce(value) {
|
|
849
|
+
return value !== null && typeof value === "object" && ONCE in value;
|
|
850
|
+
}
|
|
851
|
+
|
|
461
852
|
const RESERVED_PROPS = [
|
|
462
853
|
"children",
|
|
463
854
|
"key",
|
|
@@ -528,7 +919,7 @@ function getMemoizedPrototype(root) {
|
|
|
528
919
|
ctor = new root.constructor();
|
|
529
920
|
MEMOIZED_PROTOTYPES.set(root.constructor, ctor);
|
|
530
921
|
}
|
|
531
|
-
} catch
|
|
922
|
+
} catch {
|
|
532
923
|
}
|
|
533
924
|
return ctor;
|
|
534
925
|
}
|
|
@@ -574,6 +965,25 @@ function applyProps(object, props) {
|
|
|
574
965
|
continue;
|
|
575
966
|
}
|
|
576
967
|
if (value === void 0) continue;
|
|
968
|
+
if (isFromRef(value)) {
|
|
969
|
+
instance?.deferredRefs?.push({ prop, ref: value[FROM_REF] });
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
if (isOnce(value)) {
|
|
973
|
+
if (instance?.appliedOnce?.has(prop)) continue;
|
|
974
|
+
if (instance) {
|
|
975
|
+
instance.appliedOnce ?? (instance.appliedOnce = /* @__PURE__ */ new Set());
|
|
976
|
+
instance.appliedOnce.add(prop);
|
|
977
|
+
}
|
|
978
|
+
const { root: targetRoot, key: targetKey } = resolve(object, prop);
|
|
979
|
+
const args = value[ONCE];
|
|
980
|
+
if (typeof targetRoot[targetKey] === "function") {
|
|
981
|
+
targetRoot[targetKey](...args === true ? [] : args);
|
|
982
|
+
} else if (args !== true && args.length > 0) {
|
|
983
|
+
targetRoot[targetKey] = args[0];
|
|
984
|
+
}
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
577
987
|
let { root, key, target } = resolve(object, prop);
|
|
578
988
|
if (target === void 0 && (typeof root !== "object" || root === null)) {
|
|
579
989
|
throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`);
|
|
@@ -596,7 +1006,7 @@ function applyProps(object, props) {
|
|
|
596
1006
|
else target.set(value);
|
|
597
1007
|
} else {
|
|
598
1008
|
root[key] = value;
|
|
599
|
-
if (rootState &&
|
|
1009
|
+
if (rootState && rootState.renderer?.outputColorSpace === webgpu.SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
600
1010
|
root[key].format === webgpu.RGBAFormat && root[key].type === webgpu.UnsignedByteType) {
|
|
601
1011
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
602
1012
|
}
|
|
@@ -953,7 +1363,7 @@ function createPointerEvents(store) {
|
|
|
953
1363
|
return {
|
|
954
1364
|
priority: 1,
|
|
955
1365
|
enabled: true,
|
|
956
|
-
compute(event, state
|
|
1366
|
+
compute(event, state) {
|
|
957
1367
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
958
1368
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
959
1369
|
},
|
|
@@ -1051,331 +1461,26 @@ function notifyAlpha({ message, link }) {
|
|
|
1051
1461
|
}
|
|
1052
1462
|
}
|
|
1053
1463
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
let performanceTimeout = void 0;
|
|
1077
|
-
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
1078
|
-
const pointer = new webgpu.Vector2();
|
|
1079
|
-
const rootState = {
|
|
1080
|
-
set,
|
|
1081
|
-
get,
|
|
1082
|
-
// Mock objects that have to be configured
|
|
1083
|
-
gl: null,
|
|
1084
|
-
renderer: null,
|
|
1085
|
-
camera: null,
|
|
1086
|
-
frustum: new webgpu.Frustum(),
|
|
1087
|
-
autoUpdateFrustum: true,
|
|
1088
|
-
raycaster: null,
|
|
1089
|
-
events: { priority: 1, enabled: true, connected: false },
|
|
1090
|
-
scene: null,
|
|
1091
|
-
rootScene: null,
|
|
1092
|
-
xr: null,
|
|
1093
|
-
inspector: null,
|
|
1094
|
-
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
1095
|
-
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
1096
|
-
legacy: false,
|
|
1097
|
-
linear: false,
|
|
1098
|
-
flat: false,
|
|
1099
|
-
textureColorSpace: "srgb",
|
|
1100
|
-
isLegacy: false,
|
|
1101
|
-
webGPUSupported: false,
|
|
1102
|
-
isNative: false,
|
|
1103
|
-
controls: null,
|
|
1104
|
-
pointer,
|
|
1105
|
-
mouse: pointer,
|
|
1106
|
-
frameloop: "always",
|
|
1107
|
-
onPointerMissed: void 0,
|
|
1108
|
-
onDragOverMissed: void 0,
|
|
1109
|
-
onDropMissed: void 0,
|
|
1110
|
-
performance: {
|
|
1111
|
-
current: 1,
|
|
1112
|
-
min: 0.5,
|
|
1113
|
-
max: 1,
|
|
1114
|
-
debounce: 200,
|
|
1115
|
-
regress: () => {
|
|
1116
|
-
const state2 = get();
|
|
1117
|
-
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
1118
|
-
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
1119
|
-
performanceTimeout = setTimeout(
|
|
1120
|
-
() => setPerformanceCurrent(get().performance.max),
|
|
1121
|
-
state2.performance.debounce
|
|
1122
|
-
);
|
|
1123
|
-
}
|
|
1124
|
-
},
|
|
1125
|
-
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
1126
|
-
viewport: {
|
|
1127
|
-
initialDpr: 0,
|
|
1128
|
-
dpr: 0,
|
|
1129
|
-
width: 0,
|
|
1130
|
-
height: 0,
|
|
1131
|
-
top: 0,
|
|
1132
|
-
left: 0,
|
|
1133
|
-
aspect: 0,
|
|
1134
|
-
distance: 0,
|
|
1135
|
-
factor: 0,
|
|
1136
|
-
getCurrentViewport
|
|
1137
|
-
},
|
|
1138
|
-
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
1139
|
-
setSize: (width, height, top, left) => {
|
|
1140
|
-
const state2 = get();
|
|
1141
|
-
if (width === void 0) {
|
|
1142
|
-
set({ _sizeImperative: false });
|
|
1143
|
-
if (state2._sizeProps) {
|
|
1144
|
-
const { width: propW, height: propH } = state2._sizeProps;
|
|
1145
|
-
if (propW !== void 0 || propH !== void 0) {
|
|
1146
|
-
const currentSize = state2.size;
|
|
1147
|
-
const newSize = {
|
|
1148
|
-
width: propW ?? currentSize.width,
|
|
1149
|
-
height: propH ?? currentSize.height,
|
|
1150
|
-
top: currentSize.top,
|
|
1151
|
-
left: currentSize.left
|
|
1152
|
-
};
|
|
1153
|
-
set((s) => ({
|
|
1154
|
-
size: newSize,
|
|
1155
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
1156
|
-
}));
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
return;
|
|
1160
|
-
}
|
|
1161
|
-
const w = width;
|
|
1162
|
-
const h = height ?? width;
|
|
1163
|
-
const t = top ?? state2.size.top;
|
|
1164
|
-
const l = left ?? state2.size.left;
|
|
1165
|
-
const size = { width: w, height: h, top: t, left: l };
|
|
1166
|
-
set((s) => ({
|
|
1167
|
-
size,
|
|
1168
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
1169
|
-
_sizeImperative: true
|
|
1170
|
-
}));
|
|
1171
|
-
},
|
|
1172
|
-
setDpr: (dpr) => set((state2) => {
|
|
1173
|
-
const resolved = calculateDpr(dpr);
|
|
1174
|
-
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
1175
|
-
}),
|
|
1176
|
-
setFrameloop: (frameloop = "always") => {
|
|
1177
|
-
set(() => ({ frameloop }));
|
|
1178
|
-
},
|
|
1179
|
-
setError: (error) => set(() => ({ error })),
|
|
1180
|
-
error: null,
|
|
1181
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
|
|
1182
|
-
uniforms: {},
|
|
1183
|
-
nodes: {},
|
|
1184
|
-
textures: /* @__PURE__ */ new Map(),
|
|
1185
|
-
postProcessing: null,
|
|
1186
|
-
passes: {},
|
|
1187
|
-
_hmrVersion: 0,
|
|
1188
|
-
_sizeImperative: false,
|
|
1189
|
-
_sizeProps: null,
|
|
1190
|
-
previousRoot: void 0,
|
|
1191
|
-
internal: {
|
|
1192
|
-
// Events
|
|
1193
|
-
interaction: [],
|
|
1194
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
1195
|
-
subscribers: [],
|
|
1196
|
-
initialClick: [0, 0],
|
|
1197
|
-
initialHits: [],
|
|
1198
|
-
capturedMap: /* @__PURE__ */ new Map(),
|
|
1199
|
-
lastEvent: React__namespace.createRef(),
|
|
1200
|
-
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
1201
|
-
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
1202
|
-
// Occlusion system (WebGPU only)
|
|
1203
|
-
occlusionEnabled: false,
|
|
1204
|
-
occlusionObserver: null,
|
|
1205
|
-
occlusionCache: /* @__PURE__ */ new Map(),
|
|
1206
|
-
helperGroup: null,
|
|
1207
|
-
// Updates
|
|
1208
|
-
active: false,
|
|
1209
|
-
frames: 0,
|
|
1210
|
-
priority: 0,
|
|
1211
|
-
subscribe: (ref, priority, store) => {
|
|
1212
|
-
const internal = get().internal;
|
|
1213
|
-
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1214
|
-
internal.subscribers.push({ ref, priority, store });
|
|
1215
|
-
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
1216
|
-
return () => {
|
|
1217
|
-
const internal2 = get().internal;
|
|
1218
|
-
if (internal2?.subscribers) {
|
|
1219
|
-
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
1220
|
-
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
1221
|
-
}
|
|
1222
|
-
};
|
|
1223
|
-
},
|
|
1224
|
-
// Renderer Storage (single source of truth)
|
|
1225
|
-
actualRenderer: null,
|
|
1226
|
-
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
1227
|
-
scheduler: null
|
|
1228
|
-
}
|
|
1229
|
-
};
|
|
1230
|
-
return rootState;
|
|
1231
|
-
});
|
|
1232
|
-
const state = rootStore.getState();
|
|
1233
|
-
Object.defineProperty(state, "gl", {
|
|
1234
|
-
get() {
|
|
1235
|
-
const currentState = rootStore.getState();
|
|
1236
|
-
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
1237
|
-
const stack = new Error().stack || "";
|
|
1238
|
-
const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
|
|
1239
|
-
if (!isInternalAccess) {
|
|
1240
|
-
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
1241
|
-
notifyDepreciated({
|
|
1242
|
-
heading: "Accessing state.gl in WebGPU mode",
|
|
1243
|
-
body: "Please use state.renderer instead. state.gl is deprecated and will be removed in future versions.\n\nFor backwards compatibility, state.gl currently maps to state.renderer, but this may cause issues with libraries expecting WebGLRenderer.\n\nAccessed from:\n" + cleanedStack
|
|
1244
|
-
});
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
return currentState.internal.actualRenderer;
|
|
1248
|
-
},
|
|
1249
|
-
set(value) {
|
|
1250
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1251
|
-
},
|
|
1252
|
-
enumerable: true,
|
|
1253
|
-
configurable: true
|
|
1254
|
-
});
|
|
1255
|
-
Object.defineProperty(state, "renderer", {
|
|
1256
|
-
get() {
|
|
1257
|
-
return rootStore.getState().internal.actualRenderer;
|
|
1258
|
-
},
|
|
1259
|
-
set(value) {
|
|
1260
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1261
|
-
},
|
|
1262
|
-
enumerable: true,
|
|
1263
|
-
configurable: true
|
|
1264
|
-
});
|
|
1265
|
-
let oldScene = state.scene;
|
|
1266
|
-
rootStore.subscribe(() => {
|
|
1267
|
-
const currentState = rootStore.getState();
|
|
1268
|
-
const { scene, rootScene, set } = currentState;
|
|
1269
|
-
if (scene !== oldScene) {
|
|
1270
|
-
oldScene = scene;
|
|
1271
|
-
if (scene?.isScene && scene !== rootScene) {
|
|
1272
|
-
set({ rootScene: scene });
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
});
|
|
1276
|
-
let oldSize = state.size;
|
|
1277
|
-
let oldDpr = state.viewport.dpr;
|
|
1278
|
-
let oldCamera = state.camera;
|
|
1279
|
-
rootStore.subscribe(() => {
|
|
1280
|
-
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
1281
|
-
const actualRenderer = internal.actualRenderer;
|
|
1282
|
-
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
1283
|
-
oldSize = size;
|
|
1284
|
-
oldDpr = viewport.dpr;
|
|
1285
|
-
updateCamera(camera, size);
|
|
1286
|
-
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
1287
|
-
const updateStyle = typeof HTMLCanvasElement !== "undefined" && actualRenderer.domElement instanceof HTMLCanvasElement;
|
|
1288
|
-
actualRenderer.setSize(size.width, size.height, updateStyle);
|
|
1289
|
-
}
|
|
1290
|
-
if (camera !== oldCamera) {
|
|
1291
|
-
oldCamera = camera;
|
|
1292
|
-
const { rootScene } = rootStore.getState();
|
|
1293
|
-
if (camera && rootScene && !camera.parent) {
|
|
1294
|
-
rootScene.add(camera);
|
|
1295
|
-
}
|
|
1296
|
-
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
1297
|
-
const currentState = rootStore.getState();
|
|
1298
|
-
if (currentState.autoUpdateFrustum && camera) {
|
|
1299
|
-
updateFrustum(camera, currentState.frustum);
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
});
|
|
1303
|
-
rootStore.subscribe((state2) => invalidate(state2));
|
|
1304
|
-
return rootStore;
|
|
1305
|
-
};
|
|
1306
|
-
|
|
1307
|
-
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
1308
|
-
const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
1309
|
-
function getLoader(Proto) {
|
|
1310
|
-
if (isConstructor$1(Proto)) {
|
|
1311
|
-
let loader = memoizedLoaders.get(Proto);
|
|
1312
|
-
if (!loader) {
|
|
1313
|
-
loader = new Proto();
|
|
1314
|
-
memoizedLoaders.set(Proto, loader);
|
|
1315
|
-
}
|
|
1316
|
-
return loader;
|
|
1317
|
-
}
|
|
1318
|
-
return Proto;
|
|
1319
|
-
}
|
|
1320
|
-
function loadingFn(extensions, onProgress) {
|
|
1321
|
-
return function(Proto, input) {
|
|
1322
|
-
const loader = getLoader(Proto);
|
|
1323
|
-
if (extensions) extensions(loader);
|
|
1324
|
-
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
1325
|
-
return loader.loadAsync(input, onProgress).then((data) => {
|
|
1326
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
1327
|
-
return data;
|
|
1328
|
-
});
|
|
1329
|
-
}
|
|
1330
|
-
return new Promise(
|
|
1331
|
-
(res, reject) => loader.load(
|
|
1332
|
-
input,
|
|
1333
|
-
(data) => {
|
|
1334
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
1335
|
-
res(data);
|
|
1336
|
-
},
|
|
1337
|
-
onProgress,
|
|
1338
|
-
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
1339
|
-
)
|
|
1340
|
-
);
|
|
1341
|
-
};
|
|
1342
|
-
}
|
|
1343
|
-
function useLoader(loader, input, extensions, onProgress) {
|
|
1344
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1345
|
-
const fn = loadingFn(extensions, onProgress);
|
|
1346
|
-
const results = keys.map((key) => suspendReact.suspend(fn, [loader, key], { equal: is.equ }));
|
|
1347
|
-
return Array.isArray(input) ? results : results[0];
|
|
1348
|
-
}
|
|
1349
|
-
useLoader.preload = function(loader, input, extensions, onProgress) {
|
|
1350
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1351
|
-
keys.forEach((key) => suspendReact.preload(loadingFn(extensions, onProgress), [loader, key]));
|
|
1352
|
-
};
|
|
1353
|
-
useLoader.clear = function(loader, input) {
|
|
1354
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1355
|
-
keys.forEach((key) => suspendReact.clear([loader, key]));
|
|
1356
|
-
};
|
|
1357
|
-
useLoader.loader = getLoader;
|
|
1358
|
-
|
|
1359
|
-
var __defProp$2 = Object.defineProperty;
|
|
1360
|
-
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1361
|
-
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1362
|
-
const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
|
|
1363
|
-
class PhaseGraph {
|
|
1364
|
-
constructor() {
|
|
1365
|
-
/** Ordered list of phase nodes */
|
|
1366
|
-
__publicField$2(this, "phases", []);
|
|
1367
|
-
/** Quick lookup by name */
|
|
1368
|
-
__publicField$2(this, "phaseMap", /* @__PURE__ */ new Map());
|
|
1369
|
-
/** Cached ordered names (invalidated on changes) */
|
|
1370
|
-
__publicField$2(this, "orderedNamesCache", null);
|
|
1371
|
-
this.initializeDefaultPhases();
|
|
1372
|
-
}
|
|
1373
|
-
//* Initialization --------------------------------
|
|
1374
|
-
initializeDefaultPhases() {
|
|
1375
|
-
for (const name of DEFAULT_PHASES) {
|
|
1376
|
-
const node = { name, isAutoGenerated: false };
|
|
1377
|
-
this.phases.push(node);
|
|
1378
|
-
this.phaseMap.set(name, node);
|
|
1464
|
+
var __defProp$2 = Object.defineProperty;
|
|
1465
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1466
|
+
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1467
|
+
const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
|
|
1468
|
+
class PhaseGraph {
|
|
1469
|
+
constructor() {
|
|
1470
|
+
/** Ordered list of phase nodes */
|
|
1471
|
+
__publicField$2(this, "phases", []);
|
|
1472
|
+
/** Quick lookup by name */
|
|
1473
|
+
__publicField$2(this, "phaseMap", /* @__PURE__ */ new Map());
|
|
1474
|
+
/** Cached ordered names (invalidated on changes) */
|
|
1475
|
+
__publicField$2(this, "orderedNamesCache", null);
|
|
1476
|
+
this.initializeDefaultPhases();
|
|
1477
|
+
}
|
|
1478
|
+
//* Initialization --------------------------------
|
|
1479
|
+
initializeDefaultPhases() {
|
|
1480
|
+
for (const name of DEFAULT_PHASES) {
|
|
1481
|
+
const node = { name, isAutoGenerated: false };
|
|
1482
|
+
this.phases.push(node);
|
|
1483
|
+
this.phaseMap.set(name, node);
|
|
1379
1484
|
}
|
|
1380
1485
|
this.invalidateCache();
|
|
1381
1486
|
}
|
|
@@ -2295,98 +2400,411 @@ const _Scheduler = class _Scheduler {
|
|
|
2295
2400
|
this.triggerError(error instanceof Error ? error : new Error(String(error)));
|
|
2296
2401
|
}
|
|
2297
2402
|
}
|
|
2298
|
-
}
|
|
2299
|
-
//* Debug & Inspection Methods ================================
|
|
2300
|
-
/**
|
|
2301
|
-
* Get the total number of registered jobs across all roots.
|
|
2302
|
-
* Includes both per-root jobs and global before/after jobs.
|
|
2303
|
-
* @returns {number} Total job count
|
|
2304
|
-
*/
|
|
2305
|
-
getJobCount() {
|
|
2306
|
-
let count = 0;
|
|
2307
|
-
for (const root of this.roots.values()) {
|
|
2308
|
-
count += root.jobs.size;
|
|
2403
|
+
}
|
|
2404
|
+
//* Debug & Inspection Methods ================================
|
|
2405
|
+
/**
|
|
2406
|
+
* Get the total number of registered jobs across all roots.
|
|
2407
|
+
* Includes both per-root jobs and global before/after jobs.
|
|
2408
|
+
* @returns {number} Total job count
|
|
2409
|
+
*/
|
|
2410
|
+
getJobCount() {
|
|
2411
|
+
let count = 0;
|
|
2412
|
+
for (const root of this.roots.values()) {
|
|
2413
|
+
count += root.jobs.size;
|
|
2414
|
+
}
|
|
2415
|
+
return count + this.globalBeforeJobs.size + this.globalAfterJobs.size;
|
|
2416
|
+
}
|
|
2417
|
+
/**
|
|
2418
|
+
* Get all registered job IDs across all roots.
|
|
2419
|
+
* Includes both per-root jobs and global before/after jobs.
|
|
2420
|
+
* @returns {string[]} Array of all job IDs
|
|
2421
|
+
*/
|
|
2422
|
+
getJobIds() {
|
|
2423
|
+
const ids = [];
|
|
2424
|
+
for (const root of this.roots.values()) {
|
|
2425
|
+
ids.push(...root.jobs.keys());
|
|
2426
|
+
}
|
|
2427
|
+
ids.push(...this.globalBeforeJobs.keys());
|
|
2428
|
+
ids.push(...this.globalAfterJobs.keys());
|
|
2429
|
+
return ids;
|
|
2430
|
+
}
|
|
2431
|
+
/**
|
|
2432
|
+
* Get the number of registered roots (Canvas instances).
|
|
2433
|
+
* @returns {number} Number of registered roots
|
|
2434
|
+
*/
|
|
2435
|
+
getRootCount() {
|
|
2436
|
+
return this.roots.size;
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* Check if any user (non-system) jobs are registered in a specific phase.
|
|
2440
|
+
* Used by the default render job to know if a user has taken over rendering.
|
|
2441
|
+
*
|
|
2442
|
+
* @param phase The phase to check
|
|
2443
|
+
* @param rootId Optional root ID to check (checks all roots if not provided)
|
|
2444
|
+
* @returns true if any user jobs exist in the phase
|
|
2445
|
+
*/
|
|
2446
|
+
hasUserJobsInPhase(phase, rootId) {
|
|
2447
|
+
const rootsToCheck = rootId ? [this.roots.get(rootId)].filter(Boolean) : Array.from(this.roots.values());
|
|
2448
|
+
return rootsToCheck.some((root) => {
|
|
2449
|
+
if (!root) return false;
|
|
2450
|
+
for (const job of root.jobs.values()) {
|
|
2451
|
+
if (job.phase === phase && !job.system && job.enabled) return true;
|
|
2452
|
+
}
|
|
2453
|
+
return false;
|
|
2454
|
+
});
|
|
2455
|
+
}
|
|
2456
|
+
//* Utility Methods ================================
|
|
2457
|
+
/**
|
|
2458
|
+
* Generate a unique root ID for automatic root registration.
|
|
2459
|
+
* @returns {string} A unique root ID in the format 'root_N'
|
|
2460
|
+
*/
|
|
2461
|
+
generateRootId() {
|
|
2462
|
+
return `root_${this.nextRootIndex++}`;
|
|
2463
|
+
}
|
|
2464
|
+
/**
|
|
2465
|
+
* Generate a unique job ID.
|
|
2466
|
+
* @returns {string} A unique job ID in the format 'job_N'
|
|
2467
|
+
* @private
|
|
2468
|
+
*/
|
|
2469
|
+
generateJobId() {
|
|
2470
|
+
return `job_${this.nextJobIndex}`;
|
|
2471
|
+
}
|
|
2472
|
+
/**
|
|
2473
|
+
* Normalize before/after constraints to a Set.
|
|
2474
|
+
* Handles undefined, single string, or array inputs.
|
|
2475
|
+
* @param {string | string[] | undefined} value - The constraint value(s)
|
|
2476
|
+
* @returns {Set<string>} Normalized Set of constraint strings
|
|
2477
|
+
* @private
|
|
2478
|
+
*/
|
|
2479
|
+
normalizeConstraints(value) {
|
|
2480
|
+
if (!value) return /* @__PURE__ */ new Set();
|
|
2481
|
+
if (Array.isArray(value)) return new Set(value);
|
|
2482
|
+
return /* @__PURE__ */ new Set([value]);
|
|
2483
|
+
}
|
|
2484
|
+
};
|
|
2485
|
+
//* Static State & Methods (Singleton Usage) ================================
|
|
2486
|
+
//* Cross-Bundle Singleton Key ==============================
|
|
2487
|
+
// Use Symbol.for() to ensure scheduler is shared across bundle boundaries
|
|
2488
|
+
// This prevents issues when mixing imports from @react-three/fiber and @react-three/fiber/webgpu
|
|
2489
|
+
__publicField$1(_Scheduler, "INSTANCE_KEY", Symbol.for("@react-three/fiber.scheduler"));
|
|
2490
|
+
let Scheduler = _Scheduler;
|
|
2491
|
+
const getScheduler = () => Scheduler.get();
|
|
2492
|
+
if (hmrData) {
|
|
2493
|
+
hmrData.accept?.();
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
|
|
2497
|
+
const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React__namespace.createContext(null));
|
|
2498
|
+
const createStore = (invalidate, advance) => {
|
|
2499
|
+
const rootStore = traditional.createWithEqualityFn((set, get) => {
|
|
2500
|
+
const position = new webgpu.Vector3();
|
|
2501
|
+
const defaultTarget = new webgpu.Vector3();
|
|
2502
|
+
const tempTarget = new webgpu.Vector3();
|
|
2503
|
+
function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
|
|
2504
|
+
const { width, height, top, left } = size;
|
|
2505
|
+
const aspect = width / height;
|
|
2506
|
+
if (target.isVector3) tempTarget.copy(target);
|
|
2507
|
+
else tempTarget.set(...target);
|
|
2508
|
+
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
2509
|
+
if (isOrthographicCamera(camera)) {
|
|
2510
|
+
return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
|
|
2511
|
+
} else {
|
|
2512
|
+
const fov = camera.fov * Math.PI / 180;
|
|
2513
|
+
const h = 2 * Math.tan(fov / 2) * distance;
|
|
2514
|
+
const w = h * (width / height);
|
|
2515
|
+
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
let performanceTimeout = void 0;
|
|
2519
|
+
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
2520
|
+
const pointer = new webgpu.Vector2();
|
|
2521
|
+
const rootState = {
|
|
2522
|
+
set,
|
|
2523
|
+
get,
|
|
2524
|
+
// Mock objects that have to be configured
|
|
2525
|
+
// primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
|
|
2526
|
+
primaryStore: null,
|
|
2527
|
+
gl: null,
|
|
2528
|
+
renderer: null,
|
|
2529
|
+
camera: null,
|
|
2530
|
+
frustum: new webgpu.Frustum(),
|
|
2531
|
+
autoUpdateFrustum: true,
|
|
2532
|
+
raycaster: null,
|
|
2533
|
+
events: { priority: 1, enabled: true, connected: false },
|
|
2534
|
+
scene: null,
|
|
2535
|
+
rootScene: null,
|
|
2536
|
+
xr: null,
|
|
2537
|
+
inspector: null,
|
|
2538
|
+
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
2539
|
+
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
2540
|
+
textureColorSpace: webgpu.SRGBColorSpace,
|
|
2541
|
+
isLegacy: false,
|
|
2542
|
+
webGPUSupported: false,
|
|
2543
|
+
isNative: false,
|
|
2544
|
+
controls: null,
|
|
2545
|
+
pointer,
|
|
2546
|
+
mouse: pointer,
|
|
2547
|
+
frameloop: "always",
|
|
2548
|
+
onPointerMissed: void 0,
|
|
2549
|
+
onDragOverMissed: void 0,
|
|
2550
|
+
onDropMissed: void 0,
|
|
2551
|
+
performance: {
|
|
2552
|
+
current: 1,
|
|
2553
|
+
min: 0.5,
|
|
2554
|
+
max: 1,
|
|
2555
|
+
debounce: 200,
|
|
2556
|
+
regress: () => {
|
|
2557
|
+
const state2 = get();
|
|
2558
|
+
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
2559
|
+
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
2560
|
+
performanceTimeout = setTimeout(
|
|
2561
|
+
() => setPerformanceCurrent(get().performance.max),
|
|
2562
|
+
state2.performance.debounce
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2565
|
+
},
|
|
2566
|
+
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
2567
|
+
viewport: {
|
|
2568
|
+
initialDpr: 0,
|
|
2569
|
+
dpr: 0,
|
|
2570
|
+
width: 0,
|
|
2571
|
+
height: 0,
|
|
2572
|
+
top: 0,
|
|
2573
|
+
left: 0,
|
|
2574
|
+
aspect: 0,
|
|
2575
|
+
distance: 0,
|
|
2576
|
+
factor: 0,
|
|
2577
|
+
getCurrentViewport
|
|
2578
|
+
},
|
|
2579
|
+
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
2580
|
+
setSize: (width, height, top, left) => {
|
|
2581
|
+
const state2 = get();
|
|
2582
|
+
if (width === void 0) {
|
|
2583
|
+
set({ _sizeImperative: false });
|
|
2584
|
+
if (state2._sizeProps) {
|
|
2585
|
+
const { width: propW, height: propH } = state2._sizeProps;
|
|
2586
|
+
if (propW !== void 0 || propH !== void 0) {
|
|
2587
|
+
const currentSize = state2.size;
|
|
2588
|
+
const newSize = {
|
|
2589
|
+
width: propW ?? currentSize.width,
|
|
2590
|
+
height: propH ?? currentSize.height,
|
|
2591
|
+
top: currentSize.top,
|
|
2592
|
+
left: currentSize.left
|
|
2593
|
+
};
|
|
2594
|
+
set((s) => ({
|
|
2595
|
+
size: newSize,
|
|
2596
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
2597
|
+
}));
|
|
2598
|
+
getScheduler().invalidate();
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
return;
|
|
2602
|
+
}
|
|
2603
|
+
const w = width;
|
|
2604
|
+
const h = height ?? width;
|
|
2605
|
+
const t = top ?? state2.size.top;
|
|
2606
|
+
const l = left ?? state2.size.left;
|
|
2607
|
+
const size = { width: w, height: h, top: t, left: l };
|
|
2608
|
+
set((s) => ({
|
|
2609
|
+
size,
|
|
2610
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
2611
|
+
_sizeImperative: true
|
|
2612
|
+
}));
|
|
2613
|
+
getScheduler().invalidate();
|
|
2614
|
+
},
|
|
2615
|
+
setDpr: (dpr) => set((state2) => {
|
|
2616
|
+
const resolved = calculateDpr(dpr);
|
|
2617
|
+
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
2618
|
+
}),
|
|
2619
|
+
setFrameloop: (frameloop = "always") => {
|
|
2620
|
+
set(() => ({ frameloop }));
|
|
2621
|
+
},
|
|
2622
|
+
setError: (error) => set(() => ({ error })),
|
|
2623
|
+
error: null,
|
|
2624
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
|
|
2625
|
+
uniforms: {},
|
|
2626
|
+
nodes: {},
|
|
2627
|
+
textures: /* @__PURE__ */ new Map(),
|
|
2628
|
+
postProcessing: null,
|
|
2629
|
+
passes: {},
|
|
2630
|
+
_hmrVersion: 0,
|
|
2631
|
+
_sizeImperative: false,
|
|
2632
|
+
_sizeProps: null,
|
|
2633
|
+
previousRoot: void 0,
|
|
2634
|
+
internal: {
|
|
2635
|
+
// Events
|
|
2636
|
+
interaction: [],
|
|
2637
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2638
|
+
subscribers: [],
|
|
2639
|
+
initialClick: [0, 0],
|
|
2640
|
+
initialHits: [],
|
|
2641
|
+
capturedMap: /* @__PURE__ */ new Map(),
|
|
2642
|
+
lastEvent: React__namespace.createRef(),
|
|
2643
|
+
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2644
|
+
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2645
|
+
// Occlusion system (WebGPU only)
|
|
2646
|
+
occlusionEnabled: false,
|
|
2647
|
+
occlusionObserver: null,
|
|
2648
|
+
occlusionCache: /* @__PURE__ */ new Map(),
|
|
2649
|
+
helperGroup: null,
|
|
2650
|
+
// Updates
|
|
2651
|
+
active: false,
|
|
2652
|
+
frames: 0,
|
|
2653
|
+
priority: 0,
|
|
2654
|
+
subscribe: (ref, priority, store) => {
|
|
2655
|
+
const internal = get().internal;
|
|
2656
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
2657
|
+
internal.subscribers.push({ ref, priority, store });
|
|
2658
|
+
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
2659
|
+
return () => {
|
|
2660
|
+
const internal2 = get().internal;
|
|
2661
|
+
if (internal2?.subscribers) {
|
|
2662
|
+
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
2663
|
+
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
2664
|
+
}
|
|
2665
|
+
};
|
|
2666
|
+
},
|
|
2667
|
+
// Renderer Storage (single source of truth)
|
|
2668
|
+
actualRenderer: null,
|
|
2669
|
+
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
2670
|
+
scheduler: null
|
|
2671
|
+
}
|
|
2672
|
+
};
|
|
2673
|
+
return rootState;
|
|
2674
|
+
});
|
|
2675
|
+
const state = rootStore.getState();
|
|
2676
|
+
Object.defineProperty(state, "gl", {
|
|
2677
|
+
get() {
|
|
2678
|
+
const currentState = rootStore.getState();
|
|
2679
|
+
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
2680
|
+
const stack = new Error().stack || "";
|
|
2681
|
+
const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
|
|
2682
|
+
if (!isInternalAccess) {
|
|
2683
|
+
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
2684
|
+
notifyDepreciated({
|
|
2685
|
+
heading: "Accessing state.gl in WebGPU mode",
|
|
2686
|
+
body: "Please use state.renderer instead. state.gl is deprecated and will be removed in future versions.\n\nFor backwards compatibility, state.gl currently maps to state.renderer, but this may cause issues with libraries expecting WebGLRenderer.\n\nAccessed from:\n" + cleanedStack
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
return currentState.internal.actualRenderer;
|
|
2691
|
+
},
|
|
2692
|
+
set(value) {
|
|
2693
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
2694
|
+
},
|
|
2695
|
+
enumerable: true,
|
|
2696
|
+
configurable: true
|
|
2697
|
+
});
|
|
2698
|
+
Object.defineProperty(state, "renderer", {
|
|
2699
|
+
get() {
|
|
2700
|
+
return rootStore.getState().internal.actualRenderer;
|
|
2701
|
+
},
|
|
2702
|
+
set(value) {
|
|
2703
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
2704
|
+
},
|
|
2705
|
+
enumerable: true,
|
|
2706
|
+
configurable: true
|
|
2707
|
+
});
|
|
2708
|
+
let oldScene = state.scene;
|
|
2709
|
+
rootStore.subscribe(() => {
|
|
2710
|
+
const currentState = rootStore.getState();
|
|
2711
|
+
const { scene, rootScene, set } = currentState;
|
|
2712
|
+
if (scene !== oldScene) {
|
|
2713
|
+
oldScene = scene;
|
|
2714
|
+
if (scene?.isScene && scene !== rootScene) {
|
|
2715
|
+
set({ rootScene: scene });
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
});
|
|
2719
|
+
let oldSize = state.size;
|
|
2720
|
+
let oldDpr = state.viewport.dpr;
|
|
2721
|
+
let oldCamera = state.camera;
|
|
2722
|
+
rootStore.subscribe(() => {
|
|
2723
|
+
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
2724
|
+
const actualRenderer = internal.actualRenderer;
|
|
2725
|
+
const canvasTarget = internal.canvasTarget;
|
|
2726
|
+
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
2727
|
+
oldSize = size;
|
|
2728
|
+
oldDpr = viewport.dpr;
|
|
2729
|
+
updateCamera(camera, size);
|
|
2730
|
+
if (canvasTarget) {
|
|
2731
|
+
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2732
|
+
const updateStyle = typeof HTMLCanvasElement !== "undefined" && canvasTarget.domElement instanceof HTMLCanvasElement;
|
|
2733
|
+
canvasTarget.setSize(size.width, size.height, updateStyle);
|
|
2734
|
+
} else {
|
|
2735
|
+
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
2736
|
+
const updateStyle = typeof HTMLCanvasElement !== "undefined" && actualRenderer.domElement instanceof HTMLCanvasElement;
|
|
2737
|
+
actualRenderer.setSize(size.width, size.height, updateStyle);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
if (camera !== oldCamera) {
|
|
2741
|
+
oldCamera = camera;
|
|
2742
|
+
const { rootScene } = rootStore.getState();
|
|
2743
|
+
if (camera && rootScene && !camera.parent) {
|
|
2744
|
+
rootScene.add(camera);
|
|
2745
|
+
}
|
|
2746
|
+
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
2747
|
+
const currentState = rootStore.getState();
|
|
2748
|
+
if (currentState.autoUpdateFrustum && camera) {
|
|
2749
|
+
updateFrustum(camera, currentState.frustum);
|
|
2750
|
+
}
|
|
2309
2751
|
}
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2752
|
+
});
|
|
2753
|
+
rootStore.subscribe((state2) => invalidate(state2));
|
|
2754
|
+
return rootStore;
|
|
2755
|
+
};
|
|
2756
|
+
|
|
2757
|
+
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
2758
|
+
const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
2759
|
+
function getLoader(Proto) {
|
|
2760
|
+
if (isConstructor$1(Proto)) {
|
|
2761
|
+
let loader = memoizedLoaders.get(Proto);
|
|
2762
|
+
if (!loader) {
|
|
2763
|
+
loader = new Proto();
|
|
2764
|
+
memoizedLoaders.set(Proto, loader);
|
|
2321
2765
|
}
|
|
2322
|
-
|
|
2323
|
-
ids.push(...this.globalAfterJobs.keys());
|
|
2324
|
-
return ids;
|
|
2325
|
-
}
|
|
2326
|
-
/**
|
|
2327
|
-
* Get the number of registered roots (Canvas instances).
|
|
2328
|
-
* @returns {number} Number of registered roots
|
|
2329
|
-
*/
|
|
2330
|
-
getRootCount() {
|
|
2331
|
-
return this.roots.size;
|
|
2332
|
-
}
|
|
2333
|
-
/**
|
|
2334
|
-
* Check if any user (non-system) jobs are registered in a specific phase.
|
|
2335
|
-
* Used by the default render job to know if a user has taken over rendering.
|
|
2336
|
-
*
|
|
2337
|
-
* @param phase The phase to check
|
|
2338
|
-
* @param rootId Optional root ID to check (checks all roots if not provided)
|
|
2339
|
-
* @returns true if any user jobs exist in the phase
|
|
2340
|
-
*/
|
|
2341
|
-
hasUserJobsInPhase(phase, rootId) {
|
|
2342
|
-
const rootsToCheck = rootId ? [this.roots.get(rootId)].filter(Boolean) : Array.from(this.roots.values());
|
|
2343
|
-
return rootsToCheck.some((root) => {
|
|
2344
|
-
if (!root) return false;
|
|
2345
|
-
for (const job of root.jobs.values()) {
|
|
2346
|
-
if (job.phase === phase && !job.system && job.enabled) return true;
|
|
2347
|
-
}
|
|
2348
|
-
return false;
|
|
2349
|
-
});
|
|
2350
|
-
}
|
|
2351
|
-
//* Utility Methods ================================
|
|
2352
|
-
/**
|
|
2353
|
-
* Generate a unique root ID for automatic root registration.
|
|
2354
|
-
* @returns {string} A unique root ID in the format 'root_N'
|
|
2355
|
-
*/
|
|
2356
|
-
generateRootId() {
|
|
2357
|
-
return `root_${this.nextRootIndex++}`;
|
|
2358
|
-
}
|
|
2359
|
-
/**
|
|
2360
|
-
* Generate a unique job ID.
|
|
2361
|
-
* @returns {string} A unique job ID in the format 'job_N'
|
|
2362
|
-
* @private
|
|
2363
|
-
*/
|
|
2364
|
-
generateJobId() {
|
|
2365
|
-
return `job_${this.nextJobIndex}`;
|
|
2366
|
-
}
|
|
2367
|
-
/**
|
|
2368
|
-
* Normalize before/after constraints to a Set.
|
|
2369
|
-
* Handles undefined, single string, or array inputs.
|
|
2370
|
-
* @param {string | string[] | undefined} value - The constraint value(s)
|
|
2371
|
-
* @returns {Set<string>} Normalized Set of constraint strings
|
|
2372
|
-
* @private
|
|
2373
|
-
*/
|
|
2374
|
-
normalizeConstraints(value) {
|
|
2375
|
-
if (!value) return /* @__PURE__ */ new Set();
|
|
2376
|
-
if (Array.isArray(value)) return new Set(value);
|
|
2377
|
-
return /* @__PURE__ */ new Set([value]);
|
|
2766
|
+
return loader;
|
|
2378
2767
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
if (
|
|
2388
|
-
|
|
2768
|
+
return Proto;
|
|
2769
|
+
}
|
|
2770
|
+
function loadingFn(extensions, onProgress) {
|
|
2771
|
+
return function(Proto, input) {
|
|
2772
|
+
const loader = getLoader(Proto);
|
|
2773
|
+
if (extensions) extensions(loader);
|
|
2774
|
+
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
2775
|
+
return loader.loadAsync(input, onProgress).then((data) => {
|
|
2776
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
2777
|
+
return data;
|
|
2778
|
+
});
|
|
2779
|
+
}
|
|
2780
|
+
return new Promise(
|
|
2781
|
+
(res, reject) => loader.load(
|
|
2782
|
+
input,
|
|
2783
|
+
(data) => {
|
|
2784
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
2785
|
+
res(data);
|
|
2786
|
+
},
|
|
2787
|
+
onProgress,
|
|
2788
|
+
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
2789
|
+
)
|
|
2790
|
+
);
|
|
2791
|
+
};
|
|
2792
|
+
}
|
|
2793
|
+
function useLoader(loader, input, extensions, onProgress) {
|
|
2794
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
2795
|
+
const fn = loadingFn(extensions, onProgress);
|
|
2796
|
+
const results = keys.map((key) => suspendReact.suspend(fn, [loader, key], { equal: is.equ }));
|
|
2797
|
+
return Array.isArray(input) ? results : results[0];
|
|
2389
2798
|
}
|
|
2799
|
+
useLoader.preload = function(loader, input, extensions, onProgress) {
|
|
2800
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
2801
|
+
keys.forEach((key) => suspendReact.preload(loadingFn(extensions, onProgress), [loader, key]));
|
|
2802
|
+
};
|
|
2803
|
+
useLoader.clear = function(loader, input) {
|
|
2804
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
2805
|
+
keys.forEach((key) => suspendReact.clear([loader, key]));
|
|
2806
|
+
};
|
|
2807
|
+
useLoader.loader = getLoader;
|
|
2390
2808
|
|
|
2391
2809
|
function useFrame(callback, priorityOrOptions) {
|
|
2392
2810
|
const store = React__namespace.useContext(context);
|
|
@@ -2567,6 +2985,9 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
2567
2985
|
const textureCache = useThree((state) => state.textures);
|
|
2568
2986
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
2569
2987
|
const { onLoad, cache = false } = options;
|
|
2988
|
+
const onLoadRef = React.useRef(onLoad);
|
|
2989
|
+
onLoadRef.current = onLoad;
|
|
2990
|
+
const onLoadCalledForRef = React.useRef(null);
|
|
2570
2991
|
const urls = React.useMemo(() => getUrls(input), [input]);
|
|
2571
2992
|
const cachedResult = React.useMemo(() => {
|
|
2572
2993
|
if (!cache) return null;
|
|
@@ -2577,9 +2998,13 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
2577
2998
|
webgpu.TextureLoader,
|
|
2578
2999
|
IsObject(input) ? Object.values(input) : input
|
|
2579
3000
|
);
|
|
3001
|
+
const inputKey = urls.join("\0");
|
|
2580
3002
|
React.useLayoutEffect(() => {
|
|
2581
|
-
if (
|
|
2582
|
-
|
|
3003
|
+
if (cachedResult) return;
|
|
3004
|
+
if (onLoadCalledForRef.current === inputKey) return;
|
|
3005
|
+
onLoadCalledForRef.current = inputKey;
|
|
3006
|
+
onLoadRef.current?.(loadedTextures);
|
|
3007
|
+
}, [cachedResult, loadedTextures, inputKey]);
|
|
2583
3008
|
React.useEffect(() => {
|
|
2584
3009
|
if (cachedResult) return;
|
|
2585
3010
|
if ("initTexture" in renderer) {
|
|
@@ -2746,14 +3171,31 @@ function useTextures() {
|
|
|
2746
3171
|
}, [store]);
|
|
2747
3172
|
}
|
|
2748
3173
|
|
|
2749
|
-
function useRenderTarget(
|
|
3174
|
+
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
2750
3175
|
const isLegacy = useThree((s) => s.isLegacy);
|
|
2751
3176
|
const size = useThree((s) => s.size);
|
|
3177
|
+
let width;
|
|
3178
|
+
let height;
|
|
3179
|
+
let opts;
|
|
3180
|
+
if (typeof widthOrOptions === "object") {
|
|
3181
|
+
opts = widthOrOptions;
|
|
3182
|
+
} else if (typeof widthOrOptions === "number") {
|
|
3183
|
+
width = widthOrOptions;
|
|
3184
|
+
if (typeof heightOrOptions === "object") {
|
|
3185
|
+
height = widthOrOptions;
|
|
3186
|
+
opts = heightOrOptions;
|
|
3187
|
+
} else if (typeof heightOrOptions === "number") {
|
|
3188
|
+
height = heightOrOptions;
|
|
3189
|
+
opts = options;
|
|
3190
|
+
} else {
|
|
3191
|
+
height = widthOrOptions;
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
2752
3194
|
return React.useMemo(() => {
|
|
2753
3195
|
const w = width ?? size.width;
|
|
2754
3196
|
const h = height ?? size.height;
|
|
2755
|
-
return new webgpu.RenderTarget(w, h,
|
|
2756
|
-
}, [width, height, size.width, size.height,
|
|
3197
|
+
return new webgpu.RenderTarget(w, h, opts);
|
|
3198
|
+
}, [width, height, size.width, size.height, opts, isLegacy]);
|
|
2757
3199
|
}
|
|
2758
3200
|
|
|
2759
3201
|
function useStore() {
|
|
@@ -2803,7 +3245,7 @@ function addTail(callback) {
|
|
|
2803
3245
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
2804
3246
|
getScheduler().invalidate(frames, stackFrames);
|
|
2805
3247
|
}
|
|
2806
|
-
function advance(timestamp
|
|
3248
|
+
function advance(timestamp) {
|
|
2807
3249
|
getScheduler().step(timestamp);
|
|
2808
3250
|
}
|
|
2809
3251
|
|
|
@@ -14257,6 +14699,7 @@ function swapInstances() {
|
|
|
14257
14699
|
instance.object = instance.props.object ?? new target(...instance.props.args ?? []);
|
|
14258
14700
|
instance.object.__r3f = instance;
|
|
14259
14701
|
setFiberRef(fiber, instance.object);
|
|
14702
|
+
delete instance.appliedOnce;
|
|
14260
14703
|
applyProps(instance.object, instance.props);
|
|
14261
14704
|
if (instance.props.attach) {
|
|
14262
14705
|
attach(parent, instance);
|
|
@@ -14330,8 +14773,22 @@ const reconciler = /* @__PURE__ */ createReconciler({
|
|
|
14330
14773
|
const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
|
|
14331
14774
|
if (isTailSibling) swapInstances();
|
|
14332
14775
|
},
|
|
14333
|
-
finalizeInitialChildren: () =>
|
|
14334
|
-
|
|
14776
|
+
finalizeInitialChildren: (instance) => {
|
|
14777
|
+
for (const prop in instance.props) {
|
|
14778
|
+
if (isFromRef(instance.props[prop])) return true;
|
|
14779
|
+
}
|
|
14780
|
+
return false;
|
|
14781
|
+
},
|
|
14782
|
+
commitMount(instance) {
|
|
14783
|
+
const resolved = {};
|
|
14784
|
+
for (const prop in instance.props) {
|
|
14785
|
+
const value = instance.props[prop];
|
|
14786
|
+
if (isFromRef(value)) {
|
|
14787
|
+
const ref = value[FROM_REF];
|
|
14788
|
+
if (ref.current != null) resolved[prop] = ref.current;
|
|
14789
|
+
}
|
|
14790
|
+
}
|
|
14791
|
+
if (Object.keys(resolved).length) applyProps(instance.object, resolved);
|
|
14335
14792
|
},
|
|
14336
14793
|
getPublicInstance: (instance) => instance?.object,
|
|
14337
14794
|
prepareForCommit: () => null,
|
|
@@ -14552,6 +15009,9 @@ function createRoot(canvas) {
|
|
|
14552
15009
|
let resolve;
|
|
14553
15010
|
pending = new Promise((_resolve) => resolve = _resolve);
|
|
14554
15011
|
const {
|
|
15012
|
+
id: canvasId,
|
|
15013
|
+
primaryCanvas,
|
|
15014
|
+
scheduler: schedulerConfig,
|
|
14555
15015
|
gl: glConfig,
|
|
14556
15016
|
renderer: rendererConfig,
|
|
14557
15017
|
size: propsSize,
|
|
@@ -14559,10 +15019,7 @@ function createRoot(canvas) {
|
|
|
14559
15019
|
events,
|
|
14560
15020
|
onCreated: onCreatedCallback,
|
|
14561
15021
|
shadows = false,
|
|
14562
|
-
linear = false,
|
|
14563
|
-
flat = false,
|
|
14564
15022
|
textureColorSpace = webgpu.SRGBColorSpace,
|
|
14565
|
-
legacy = false,
|
|
14566
15023
|
orthographic = false,
|
|
14567
15024
|
frameloop = "always",
|
|
14568
15025
|
dpr = [1, 2],
|
|
@@ -14574,11 +15031,13 @@ function createRoot(canvas) {
|
|
|
14574
15031
|
onDropMissed,
|
|
14575
15032
|
autoUpdateFrustum = true,
|
|
14576
15033
|
occlusion = false,
|
|
14577
|
-
_sizeProps
|
|
15034
|
+
_sizeProps,
|
|
15035
|
+
forceEven
|
|
14578
15036
|
} = props;
|
|
14579
15037
|
const state = store.getState();
|
|
14580
15038
|
const defaultGPUProps = {
|
|
14581
|
-
canvas
|
|
15039
|
+
canvas,
|
|
15040
|
+
antialias: true
|
|
14582
15041
|
};
|
|
14583
15042
|
if (glConfig && !R3F_BUILD_LEGACY) {
|
|
14584
15043
|
throw new Error(
|
|
@@ -14589,7 +15048,27 @@ function createRoot(canvas) {
|
|
|
14589
15048
|
throw new Error("Cannot use both gl and renderer props at the same time");
|
|
14590
15049
|
}
|
|
14591
15050
|
let renderer = state.internal.actualRenderer;
|
|
14592
|
-
if (!state.internal.actualRenderer) {
|
|
15051
|
+
if (primaryCanvas && !state.internal.actualRenderer) {
|
|
15052
|
+
const primary = await waitForPrimary(primaryCanvas);
|
|
15053
|
+
renderer = primary.renderer;
|
|
15054
|
+
state.internal.actualRenderer = renderer;
|
|
15055
|
+
const canvasTarget = new webgpu.CanvasTarget(canvas);
|
|
15056
|
+
primary.store.setState((prev) => ({
|
|
15057
|
+
internal: { ...prev.internal, isMultiCanvas: true }
|
|
15058
|
+
}));
|
|
15059
|
+
state.set((prev) => ({
|
|
15060
|
+
webGPUSupported: primary.store.getState().webGPUSupported,
|
|
15061
|
+
renderer,
|
|
15062
|
+
primaryStore: primary.store,
|
|
15063
|
+
internal: {
|
|
15064
|
+
...prev.internal,
|
|
15065
|
+
canvasTarget,
|
|
15066
|
+
isMultiCanvas: true,
|
|
15067
|
+
isSecondary: true,
|
|
15068
|
+
targetId: primaryCanvas
|
|
15069
|
+
}
|
|
15070
|
+
}));
|
|
15071
|
+
} else if (!state.internal.actualRenderer) {
|
|
14593
15072
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
|
|
14594
15073
|
if (!renderer.hasInitialized?.()) {
|
|
14595
15074
|
await renderer.init();
|
|
@@ -14597,7 +15076,18 @@ function createRoot(canvas) {
|
|
|
14597
15076
|
const backend = renderer.backend;
|
|
14598
15077
|
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
14599
15078
|
state.internal.actualRenderer = renderer;
|
|
14600
|
-
state.set({ webGPUSupported: isWebGPUBackend, renderer });
|
|
15079
|
+
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
15080
|
+
if (canvasId && !state.internal.isSecondary) {
|
|
15081
|
+
const canvasTarget = new webgpu.CanvasTarget(canvas);
|
|
15082
|
+
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
15083
|
+
state.set((prev) => ({
|
|
15084
|
+
internal: {
|
|
15085
|
+
...prev.internal,
|
|
15086
|
+
canvasTarget,
|
|
15087
|
+
unregisterPrimary
|
|
15088
|
+
}
|
|
15089
|
+
}));
|
|
15090
|
+
}
|
|
14601
15091
|
}
|
|
14602
15092
|
let raycaster = state.raycaster;
|
|
14603
15093
|
if (!raycaster) state.set({ raycaster: raycaster = new webgpu.Raycaster() });
|
|
@@ -14606,6 +15096,7 @@ function createRoot(canvas) {
|
|
|
14606
15096
|
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
14607
15097
|
applyProps(raycaster, { params: { ...raycaster.params, ...params } });
|
|
14608
15098
|
}
|
|
15099
|
+
let tempCamera = state.camera;
|
|
14609
15100
|
if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
|
|
14610
15101
|
lastCamera = cameraOptions;
|
|
14611
15102
|
const isCamera = cameraOptions?.isCamera;
|
|
@@ -14625,6 +15116,7 @@ function createRoot(canvas) {
|
|
|
14625
15116
|
if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
|
|
14626
15117
|
}
|
|
14627
15118
|
state.set({ camera });
|
|
15119
|
+
tempCamera = camera;
|
|
14628
15120
|
raycaster.camera = camera;
|
|
14629
15121
|
}
|
|
14630
15122
|
if (!state.scene) {
|
|
@@ -14642,7 +15134,7 @@ function createRoot(canvas) {
|
|
|
14642
15134
|
rootScene: scene,
|
|
14643
15135
|
internal: { ...prev.internal, container: scene }
|
|
14644
15136
|
}));
|
|
14645
|
-
const camera =
|
|
15137
|
+
const camera = tempCamera;
|
|
14646
15138
|
if (camera && !camera.parent) scene.add(camera);
|
|
14647
15139
|
}
|
|
14648
15140
|
if (events && !state.events.handlers) {
|
|
@@ -14659,6 +15151,9 @@ function createRoot(canvas) {
|
|
|
14659
15151
|
if (_sizeProps !== void 0) {
|
|
14660
15152
|
state.set({ _sizeProps });
|
|
14661
15153
|
}
|
|
15154
|
+
if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
|
|
15155
|
+
state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
|
|
15156
|
+
}
|
|
14662
15157
|
const size = computeInitialSize(canvas, propsSize);
|
|
14663
15158
|
if (!state._sizeImperative && !is.equ(size, state.size, shallowLoose)) {
|
|
14664
15159
|
const wasImperative = state._sizeImperative;
|
|
@@ -14688,7 +15183,7 @@ function createRoot(canvas) {
|
|
|
14688
15183
|
const handleXRFrame = (timestamp, frame) => {
|
|
14689
15184
|
const state2 = store.getState();
|
|
14690
15185
|
if (state2.frameloop === "never") return;
|
|
14691
|
-
advance(timestamp
|
|
15186
|
+
advance(timestamp);
|
|
14692
15187
|
};
|
|
14693
15188
|
const actualRenderer = state.internal.actualRenderer;
|
|
14694
15189
|
const handleSessionChange = () => {
|
|
@@ -14700,16 +15195,16 @@ function createRoot(canvas) {
|
|
|
14700
15195
|
};
|
|
14701
15196
|
const xr = {
|
|
14702
15197
|
connect() {
|
|
14703
|
-
const { gl, renderer: renderer2
|
|
14704
|
-
const
|
|
14705
|
-
|
|
14706
|
-
|
|
15198
|
+
const { gl, renderer: renderer2 } = store.getState();
|
|
15199
|
+
const xrManager = (renderer2 || gl).xr;
|
|
15200
|
+
xrManager.addEventListener("sessionstart", handleSessionChange);
|
|
15201
|
+
xrManager.addEventListener("sessionend", handleSessionChange);
|
|
14707
15202
|
},
|
|
14708
15203
|
disconnect() {
|
|
14709
|
-
const { gl, renderer: renderer2
|
|
14710
|
-
const
|
|
14711
|
-
|
|
14712
|
-
|
|
15204
|
+
const { gl, renderer: renderer2 } = store.getState();
|
|
15205
|
+
const xrManager = (renderer2 || gl).xr;
|
|
15206
|
+
xrManager.removeEventListener("sessionstart", handleSessionChange);
|
|
15207
|
+
xrManager.removeEventListener("sessionend", handleSessionChange);
|
|
14713
15208
|
}
|
|
14714
15209
|
};
|
|
14715
15210
|
if (typeof renderer.xr?.addEventListener === "function") xr.connect();
|
|
@@ -14737,6 +15232,10 @@ function createRoot(canvas) {
|
|
|
14737
15232
|
renderer.shadowMap.needsUpdate = true;
|
|
14738
15233
|
}
|
|
14739
15234
|
}
|
|
15235
|
+
if (!configured) {
|
|
15236
|
+
renderer.outputColorSpace = webgpu.SRGBColorSpace;
|
|
15237
|
+
renderer.toneMapping = webgpu.ACESFilmicToneMapping;
|
|
15238
|
+
}
|
|
14740
15239
|
if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
|
|
14741
15240
|
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
14742
15241
|
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
@@ -14753,11 +15252,26 @@ function createRoot(canvas) {
|
|
|
14753
15252
|
const scheduler = getScheduler();
|
|
14754
15253
|
const rootId = state.internal.rootId;
|
|
14755
15254
|
if (!rootId) {
|
|
14756
|
-
const newRootId = scheduler.generateRootId();
|
|
15255
|
+
const newRootId = canvasId || scheduler.generateRootId();
|
|
14757
15256
|
const unregisterRoot = scheduler.registerRoot(newRootId, {
|
|
14758
15257
|
getState: () => store.getState(),
|
|
14759
15258
|
onError: (err) => store.getState().setError(err)
|
|
14760
15259
|
});
|
|
15260
|
+
const unregisterCanvasTarget = scheduler.register(
|
|
15261
|
+
() => {
|
|
15262
|
+
const state2 = store.getState();
|
|
15263
|
+
if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
|
|
15264
|
+
const renderer2 = state2.internal.actualRenderer;
|
|
15265
|
+
renderer2.setCanvasTarget(state2.internal.canvasTarget);
|
|
15266
|
+
}
|
|
15267
|
+
},
|
|
15268
|
+
{
|
|
15269
|
+
id: `${newRootId}_canvasTarget`,
|
|
15270
|
+
rootId: newRootId,
|
|
15271
|
+
phase: "start",
|
|
15272
|
+
system: true
|
|
15273
|
+
}
|
|
15274
|
+
);
|
|
14761
15275
|
const unregisterFrustum = scheduler.register(
|
|
14762
15276
|
() => {
|
|
14763
15277
|
const state2 = store.getState();
|
|
@@ -14799,11 +15313,15 @@ function createRoot(canvas) {
|
|
|
14799
15313
|
}
|
|
14800
15314
|
},
|
|
14801
15315
|
{
|
|
14802
|
-
|
|
15316
|
+
// Use canvas ID directly as job ID if available, otherwise use generated rootId
|
|
15317
|
+
id: canvasId || `${newRootId}_render`,
|
|
14803
15318
|
rootId: newRootId,
|
|
14804
15319
|
phase: "render",
|
|
14805
|
-
system: true
|
|
15320
|
+
system: true,
|
|
14806
15321
|
// Internal flag: this is a system job, not user-controlled
|
|
15322
|
+
// Apply scheduler config for render ordering and rate limiting
|
|
15323
|
+
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
15324
|
+
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14807
15325
|
}
|
|
14808
15326
|
);
|
|
14809
15327
|
state.set((state2) => ({
|
|
@@ -14812,6 +15330,7 @@ function createRoot(canvas) {
|
|
|
14812
15330
|
rootId: newRootId,
|
|
14813
15331
|
unregisterRoot: () => {
|
|
14814
15332
|
unregisterRoot();
|
|
15333
|
+
unregisterCanvasTarget();
|
|
14815
15334
|
unregisterFrustum();
|
|
14816
15335
|
unregisterVisibility();
|
|
14817
15336
|
unregisterRender();
|
|
@@ -14870,15 +15389,24 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14870
15389
|
const renderer = state.internal.actualRenderer;
|
|
14871
15390
|
const unregisterRoot = state.internal.unregisterRoot;
|
|
14872
15391
|
if (unregisterRoot) unregisterRoot();
|
|
15392
|
+
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
15393
|
+
if (unregisterPrimary) unregisterPrimary();
|
|
15394
|
+
const canvasTarget = state.internal.canvasTarget;
|
|
15395
|
+
if (canvasTarget?.dispose) canvasTarget.dispose();
|
|
14873
15396
|
state.events.disconnect?.();
|
|
14874
15397
|
cleanupHelperGroup(root.store);
|
|
14875
|
-
renderer
|
|
14876
|
-
|
|
14877
|
-
|
|
15398
|
+
if (state.isLegacy && renderer) {
|
|
15399
|
+
;
|
|
15400
|
+
renderer.renderLists?.dispose?.();
|
|
15401
|
+
renderer.forceContextLoss?.();
|
|
15402
|
+
}
|
|
15403
|
+
if (!state.internal.isSecondary) {
|
|
15404
|
+
if (renderer?.xr) state.xr.disconnect();
|
|
15405
|
+
}
|
|
14878
15406
|
dispose(state.scene);
|
|
14879
15407
|
_roots.delete(canvas);
|
|
14880
15408
|
if (callback) callback(canvas);
|
|
14881
|
-
} catch
|
|
15409
|
+
} catch {
|
|
14882
15410
|
}
|
|
14883
15411
|
}, 500);
|
|
14884
15412
|
}
|
|
@@ -14886,36 +15414,34 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14886
15414
|
}
|
|
14887
15415
|
}
|
|
14888
15416
|
function createPortal(children, container, state) {
|
|
14889
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15417
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children, container, state });
|
|
14890
15418
|
}
|
|
14891
|
-
function
|
|
15419
|
+
function Portal({ children, container, state }) {
|
|
14892
15420
|
const isRef = React.useCallback((obj) => obj && "current" in obj, []);
|
|
14893
|
-
const [resolvedContainer,
|
|
15421
|
+
const [resolvedContainer, _setResolvedContainer] = React.useState(() => {
|
|
14894
15422
|
if (isRef(container)) return container.current ?? null;
|
|
14895
15423
|
return container;
|
|
14896
15424
|
});
|
|
15425
|
+
const setResolvedContainer = React.useCallback(
|
|
15426
|
+
(newContainer) => {
|
|
15427
|
+
if (!newContainer || newContainer === resolvedContainer) return;
|
|
15428
|
+
_setResolvedContainer(isRef(newContainer) ? newContainer.current : newContainer);
|
|
15429
|
+
},
|
|
15430
|
+
[resolvedContainer, _setResolvedContainer, isRef]
|
|
15431
|
+
);
|
|
14897
15432
|
React.useMemo(() => {
|
|
14898
|
-
if (isRef(container)) {
|
|
14899
|
-
|
|
14900
|
-
|
|
14901
|
-
|
|
14902
|
-
const updated = container.current;
|
|
14903
|
-
if (updated && updated !== resolvedContainer) {
|
|
14904
|
-
setResolvedContainer(updated);
|
|
14905
|
-
}
|
|
14906
|
-
});
|
|
14907
|
-
} else if (current !== resolvedContainer) {
|
|
14908
|
-
setResolvedContainer(current);
|
|
14909
|
-
}
|
|
14910
|
-
} else if (container !== resolvedContainer) {
|
|
14911
|
-
setResolvedContainer(container);
|
|
15433
|
+
if (isRef(container) && !container.current) {
|
|
15434
|
+
return queueMicrotask(() => {
|
|
15435
|
+
setResolvedContainer(container.current);
|
|
15436
|
+
});
|
|
14912
15437
|
}
|
|
14913
|
-
|
|
15438
|
+
setResolvedContainer(container);
|
|
15439
|
+
}, [container, isRef, setResolvedContainer]);
|
|
14914
15440
|
if (!resolvedContainer) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
14915
15441
|
const portalKey = resolvedContainer.uuid ?? `portal-${resolvedContainer.id ?? "unknown"}`;
|
|
14916
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15442
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PortalInner, { children, container: resolvedContainer, state }, portalKey);
|
|
14917
15443
|
}
|
|
14918
|
-
function
|
|
15444
|
+
function PortalInner({ state = {}, children, container }) {
|
|
14919
15445
|
const { events, size, injectScene = true, ...rest } = state;
|
|
14920
15446
|
const previousRoot = useStore();
|
|
14921
15447
|
const [raycaster] = React.useState(() => new webgpu.Raycaster());
|
|
@@ -14936,11 +15462,12 @@ function Portal({ state = {}, children, container }) {
|
|
|
14936
15462
|
};
|
|
14937
15463
|
}, [portalScene, container, injectScene]);
|
|
14938
15464
|
const inject = useMutableCallback((rootState, injectState) => {
|
|
15465
|
+
const resolvedSize = { ...rootState.size, ...injectState.size, ...size };
|
|
14939
15466
|
let viewport = void 0;
|
|
14940
|
-
if (injectState.camera && size) {
|
|
15467
|
+
if (injectState.camera && (size || injectState.size)) {
|
|
14941
15468
|
const camera = injectState.camera;
|
|
14942
|
-
viewport = rootState.viewport.getCurrentViewport(camera, new webgpu.Vector3(),
|
|
14943
|
-
if (camera !== rootState.camera) updateCamera(camera,
|
|
15469
|
+
viewport = rootState.viewport.getCurrentViewport(camera, new webgpu.Vector3(), resolvedSize);
|
|
15470
|
+
if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
|
|
14944
15471
|
}
|
|
14945
15472
|
return {
|
|
14946
15473
|
// The intersect consists of the previous root state
|
|
@@ -14957,7 +15484,7 @@ function Portal({ state = {}, children, container }) {
|
|
|
14957
15484
|
previousRoot,
|
|
14958
15485
|
// Events, size and viewport can be overridden by the inject layer
|
|
14959
15486
|
events: { ...rootState.events, ...injectState.events, ...events },
|
|
14960
|
-
size:
|
|
15487
|
+
size: resolvedSize,
|
|
14961
15488
|
viewport: { ...rootState.viewport, ...viewport },
|
|
14962
15489
|
// Layers are allowed to override events
|
|
14963
15490
|
setEvents: (events2) => injectState.set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
|
|
@@ -14991,15 +15518,13 @@ function CanvasImpl({
|
|
|
14991
15518
|
fallback,
|
|
14992
15519
|
resize,
|
|
14993
15520
|
style,
|
|
15521
|
+
id,
|
|
14994
15522
|
gl,
|
|
14995
|
-
renderer,
|
|
15523
|
+
renderer: rendererProp,
|
|
14996
15524
|
events = createPointerEvents,
|
|
14997
15525
|
eventSource,
|
|
14998
15526
|
eventPrefix,
|
|
14999
15527
|
shadows,
|
|
15000
|
-
linear,
|
|
15001
|
-
flat,
|
|
15002
|
-
legacy,
|
|
15003
15528
|
orthographic,
|
|
15004
15529
|
frameloop,
|
|
15005
15530
|
dpr,
|
|
@@ -15014,10 +15539,43 @@ function CanvasImpl({
|
|
|
15014
15539
|
hmr,
|
|
15015
15540
|
width,
|
|
15016
15541
|
height,
|
|
15542
|
+
background,
|
|
15543
|
+
forceEven,
|
|
15017
15544
|
...props
|
|
15018
15545
|
}) {
|
|
15546
|
+
const { primaryCanvas, scheduler, ...rendererConfig } = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp) ? rendererProp : { primaryCanvas: void 0, scheduler: void 0 };
|
|
15547
|
+
const renderer = Object.keys(rendererConfig).length > 0 ? rendererConfig : rendererProp;
|
|
15019
15548
|
React__namespace.useMemo(() => extend(THREE), []);
|
|
15020
15549
|
const Bridge = useBridge();
|
|
15550
|
+
const backgroundProps = React__namespace.useMemo(() => {
|
|
15551
|
+
if (!background) return null;
|
|
15552
|
+
if (typeof background === "object" && !background.isColor) {
|
|
15553
|
+
const { backgroundMap, envMap, files, preset, ...rest } = background;
|
|
15554
|
+
return {
|
|
15555
|
+
...rest,
|
|
15556
|
+
preset,
|
|
15557
|
+
files: envMap || files,
|
|
15558
|
+
backgroundFiles: backgroundMap,
|
|
15559
|
+
background: true
|
|
15560
|
+
};
|
|
15561
|
+
}
|
|
15562
|
+
if (typeof background === "number") {
|
|
15563
|
+
return { color: background, background: true };
|
|
15564
|
+
}
|
|
15565
|
+
if (typeof background === "string") {
|
|
15566
|
+
if (background in presetsObj) {
|
|
15567
|
+
return { preset: background, background: true };
|
|
15568
|
+
}
|
|
15569
|
+
if (/^(https?:\/\/|\/|\.\/|\.\.\/)|\\.(hdr|exr|jpg|jpeg|png|webp|gif)$/i.test(background)) {
|
|
15570
|
+
return { files: background, background: true };
|
|
15571
|
+
}
|
|
15572
|
+
return { color: background, background: true };
|
|
15573
|
+
}
|
|
15574
|
+
if (background.isColor) {
|
|
15575
|
+
return { color: background, background: true };
|
|
15576
|
+
}
|
|
15577
|
+
return null;
|
|
15578
|
+
}, [background]);
|
|
15021
15579
|
const hasInitialSizeRef = React__namespace.useRef(false);
|
|
15022
15580
|
const measureConfig = React__namespace.useMemo(() => {
|
|
15023
15581
|
if (!hasInitialSizeRef.current) {
|
|
@@ -15034,15 +15592,20 @@ function CanvasImpl({
|
|
|
15034
15592
|
};
|
|
15035
15593
|
}, [resize, hasInitialSizeRef.current]);
|
|
15036
15594
|
const [containerRef, containerRect] = useMeasure__default(measureConfig);
|
|
15037
|
-
const effectiveSize = React__namespace.useMemo(
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
|
|
15595
|
+
const effectiveSize = React__namespace.useMemo(() => {
|
|
15596
|
+
let w = width ?? containerRect.width;
|
|
15597
|
+
let h = height ?? containerRect.height;
|
|
15598
|
+
if (forceEven) {
|
|
15599
|
+
w = Math.ceil(w / 2) * 2;
|
|
15600
|
+
h = Math.ceil(h / 2) * 2;
|
|
15601
|
+
}
|
|
15602
|
+
return {
|
|
15603
|
+
width: w,
|
|
15604
|
+
height: h,
|
|
15041
15605
|
top: containerRect.top,
|
|
15042
15606
|
left: containerRect.left
|
|
15043
|
-
}
|
|
15044
|
-
|
|
15045
|
-
);
|
|
15607
|
+
};
|
|
15608
|
+
}, [width, height, containerRect, forceEven]);
|
|
15046
15609
|
if (!hasInitialSizeRef.current && effectiveSize.width > 0 && effectiveSize.height > 0) {
|
|
15047
15610
|
hasInitialSizeRef.current = true;
|
|
15048
15611
|
}
|
|
@@ -15082,14 +15645,14 @@ function CanvasImpl({
|
|
|
15082
15645
|
async function run() {
|
|
15083
15646
|
if (!effectActiveRef.current || !root.current) return;
|
|
15084
15647
|
await root.current.configure({
|
|
15648
|
+
id,
|
|
15649
|
+
primaryCanvas,
|
|
15650
|
+
scheduler,
|
|
15085
15651
|
gl,
|
|
15086
15652
|
renderer,
|
|
15087
15653
|
scene,
|
|
15088
15654
|
events,
|
|
15089
15655
|
shadows,
|
|
15090
|
-
linear,
|
|
15091
|
-
flat,
|
|
15092
|
-
legacy,
|
|
15093
15656
|
orthographic,
|
|
15094
15657
|
frameloop,
|
|
15095
15658
|
dpr,
|
|
@@ -15099,6 +15662,7 @@ function CanvasImpl({
|
|
|
15099
15662
|
size: effectiveSize,
|
|
15100
15663
|
// Store size props for reset functionality
|
|
15101
15664
|
_sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
|
|
15665
|
+
forceEven,
|
|
15102
15666
|
// Pass mutable reference to onPointerMissed so it's free to update
|
|
15103
15667
|
onPointerMissed: (...args) => handlePointerMissed.current?.(...args),
|
|
15104
15668
|
onDragOverMissed: (...args) => handleDragOverMissed.current?.(...args),
|
|
@@ -15122,7 +15686,10 @@ function CanvasImpl({
|
|
|
15122
15686
|
});
|
|
15123
15687
|
if (!effectActiveRef.current || !root.current) return;
|
|
15124
15688
|
root.current.render(
|
|
15125
|
-
/* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.
|
|
15689
|
+
/* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Block, { set: setBlock }), children: [
|
|
15690
|
+
backgroundProps && /* @__PURE__ */ jsxRuntime.jsx(Environment, { ...backgroundProps }),
|
|
15691
|
+
children ?? null
|
|
15692
|
+
] }) }) })
|
|
15126
15693
|
);
|
|
15127
15694
|
}
|
|
15128
15695
|
run();
|
|
@@ -15149,14 +15716,16 @@ function CanvasImpl({
|
|
|
15149
15716
|
const canvas = canvasRef.current;
|
|
15150
15717
|
if (!canvas) return;
|
|
15151
15718
|
const handleHMR = () => {
|
|
15152
|
-
|
|
15153
|
-
|
|
15154
|
-
rootEntry
|
|
15155
|
-
|
|
15156
|
-
|
|
15157
|
-
|
|
15158
|
-
|
|
15159
|
-
|
|
15719
|
+
queueMicrotask(() => {
|
|
15720
|
+
const rootEntry = _roots.get(canvas);
|
|
15721
|
+
if (rootEntry?.store) {
|
|
15722
|
+
rootEntry.store.setState((state) => ({
|
|
15723
|
+
nodes: {},
|
|
15724
|
+
uniforms: {},
|
|
15725
|
+
_hmrVersion: state._hmrVersion + 1
|
|
15726
|
+
}));
|
|
15727
|
+
}
|
|
15728
|
+
});
|
|
15160
15729
|
};
|
|
15161
15730
|
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
|
|
15162
15731
|
const hot = undefined;
|
|
@@ -15185,7 +15754,7 @@ function CanvasImpl({
|
|
|
15185
15754
|
...style
|
|
15186
15755
|
},
|
|
15187
15756
|
...props,
|
|
15188
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx("canvas", { ref: canvasRef, className: "r3f-canvas", style: { display: "block" }, children: fallback }) })
|
|
15757
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx("canvas", { ref: canvasRef, id, className: "r3f-canvas", style: { display: "block" }, children: fallback }) })
|
|
15189
15758
|
}
|
|
15190
15759
|
);
|
|
15191
15760
|
}
|
|
@@ -15258,6 +15827,22 @@ let ScopedStore = _ScopedStore;
|
|
|
15258
15827
|
function createScopedStore(data) {
|
|
15259
15828
|
return new ScopedStore(data);
|
|
15260
15829
|
}
|
|
15830
|
+
function createLazyCreatorState(state) {
|
|
15831
|
+
let _uniforms = null;
|
|
15832
|
+
let _nodes = null;
|
|
15833
|
+
return Object.create(state, {
|
|
15834
|
+
uniforms: {
|
|
15835
|
+
get() {
|
|
15836
|
+
return _uniforms ?? (_uniforms = createScopedStore(state.uniforms));
|
|
15837
|
+
}
|
|
15838
|
+
},
|
|
15839
|
+
nodes: {
|
|
15840
|
+
get() {
|
|
15841
|
+
return _nodes ?? (_nodes = createScopedStore(state.nodes));
|
|
15842
|
+
}
|
|
15843
|
+
}
|
|
15844
|
+
});
|
|
15845
|
+
}
|
|
15261
15846
|
|
|
15262
15847
|
function addTexture(set, key, value) {
|
|
15263
15848
|
set((state) => {
|
|
@@ -15298,6 +15883,27 @@ function createTextureOperations(set) {
|
|
|
15298
15883
|
removeMultiple: (keys) => removeTextures(set, keys)
|
|
15299
15884
|
};
|
|
15300
15885
|
}
|
|
15886
|
+
function extractTSLValue(value) {
|
|
15887
|
+
if (value === null || value === void 0) return value;
|
|
15888
|
+
if (typeof value !== "object") return value;
|
|
15889
|
+
const node = value;
|
|
15890
|
+
if (!node.isNode) return value;
|
|
15891
|
+
if (node.isConstNode) {
|
|
15892
|
+
return node.value;
|
|
15893
|
+
}
|
|
15894
|
+
if ("value" in node) {
|
|
15895
|
+
let extractedValue = node.value;
|
|
15896
|
+
if (typeof node.traverse === "function") {
|
|
15897
|
+
node.traverse((n) => {
|
|
15898
|
+
if (n.isConstNode) {
|
|
15899
|
+
extractedValue = n.value;
|
|
15900
|
+
}
|
|
15901
|
+
});
|
|
15902
|
+
}
|
|
15903
|
+
return extractedValue;
|
|
15904
|
+
}
|
|
15905
|
+
return value;
|
|
15906
|
+
}
|
|
15301
15907
|
function vectorize(inObject) {
|
|
15302
15908
|
if (inObject === null || inObject === void 0) return inObject;
|
|
15303
15909
|
if (typeof inObject === "string") {
|
|
@@ -15310,6 +15916,9 @@ function vectorize(inObject) {
|
|
|
15310
15916
|
}
|
|
15311
15917
|
if (typeof inObject !== "object") return inObject;
|
|
15312
15918
|
const obj = inObject;
|
|
15919
|
+
if (obj.isNode) {
|
|
15920
|
+
return extractTSLValue(inObject);
|
|
15921
|
+
}
|
|
15313
15922
|
if (obj.isVector2 || obj.isVector3 || obj.isVector4) return inObject;
|
|
15314
15923
|
if (obj.isMatrix3 || obj.isMatrix4) return inObject;
|
|
15315
15924
|
if (obj.isColor || obj.isEuler || obj.isQuaternion || obj.isSpherical) return inObject;
|
|
@@ -15375,17 +15984,14 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15375
15984
|
const rebuildUniforms = React.useCallback(
|
|
15376
15985
|
(targetScope) => {
|
|
15377
15986
|
store.setState((state) => {
|
|
15378
|
-
let newUniforms =
|
|
15987
|
+
let newUniforms = {};
|
|
15379
15988
|
if (targetScope && targetScope !== "root") {
|
|
15380
15989
|
const { [targetScope]: _, ...rest } = state.uniforms;
|
|
15381
15990
|
newUniforms = rest;
|
|
15382
15991
|
} else if (targetScope === "root") {
|
|
15383
|
-
newUniforms = {};
|
|
15384
15992
|
for (const [key, value] of Object.entries(state.uniforms)) {
|
|
15385
15993
|
if (!isUniformNode$1(value)) newUniforms[key] = value;
|
|
15386
15994
|
}
|
|
15387
|
-
} else {
|
|
15388
|
-
newUniforms = {};
|
|
15389
15995
|
}
|
|
15390
15996
|
return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
|
|
15391
15997
|
});
|
|
@@ -15393,20 +15999,26 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15393
15999
|
[store]
|
|
15394
16000
|
);
|
|
15395
16001
|
const inputForMemoization = React.useMemo(() => {
|
|
16002
|
+
let raw = creatorOrScope;
|
|
15396
16003
|
if (is.fun(creatorOrScope)) {
|
|
15397
|
-
const
|
|
15398
|
-
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
16004
|
+
const wrappedState = createLazyCreatorState(store.getState());
|
|
16005
|
+
raw = creatorOrScope(wrappedState);
|
|
16006
|
+
}
|
|
16007
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
16008
|
+
const normalized = {};
|
|
16009
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
16010
|
+
normalized[key] = vectorize(value);
|
|
16011
|
+
}
|
|
16012
|
+
return normalized;
|
|
15404
16013
|
}
|
|
15405
|
-
return
|
|
16014
|
+
return raw;
|
|
15406
16015
|
}, [creatorOrScope, store]);
|
|
15407
16016
|
const memoizedInput = useCompareMemoize(inputForMemoization);
|
|
15408
16017
|
const isReader = memoizedInput === void 0 || typeof memoizedInput === "string";
|
|
15409
16018
|
const storeUniforms = useThree((s) => s.uniforms);
|
|
16019
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16020
|
+
const readerDep = isReader ? storeUniforms : null;
|
|
16021
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
15410
16022
|
const uniforms = React.useMemo(() => {
|
|
15411
16023
|
if (memoizedInput === void 0) {
|
|
15412
16024
|
return storeUniforms;
|
|
@@ -15461,28 +16073,19 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15461
16073
|
}
|
|
15462
16074
|
}
|
|
15463
16075
|
return result;
|
|
15464
|
-
}, [
|
|
15465
|
-
store,
|
|
15466
|
-
memoizedInput,
|
|
15467
|
-
scope,
|
|
15468
|
-
// Only include storeUniforms in deps for reader modes to enable reactivity
|
|
15469
|
-
isReader ? storeUniforms : null
|
|
15470
|
-
]);
|
|
16076
|
+
}, [store, memoizedInput, scope, readerDep, creatorDep]);
|
|
15471
16077
|
return { ...uniforms, removeUniforms: removeUniforms2, clearUniforms, rebuildUniforms };
|
|
15472
16078
|
}
|
|
15473
16079
|
function rebuildAllUniforms(store, scope) {
|
|
15474
16080
|
store.setState((state) => {
|
|
15475
|
-
let newUniforms =
|
|
16081
|
+
let newUniforms = {};
|
|
15476
16082
|
if (scope && scope !== "root") {
|
|
15477
16083
|
const { [scope]: _, ...rest } = state.uniforms;
|
|
15478
16084
|
newUniforms = rest;
|
|
15479
16085
|
} else if (scope === "root") {
|
|
15480
|
-
newUniforms = {};
|
|
15481
16086
|
for (const [key, value] of Object.entries(state.uniforms)) {
|
|
15482
16087
|
if (!isUniformNode$1(value)) newUniforms[key] = value;
|
|
15483
16088
|
}
|
|
15484
|
-
} else {
|
|
15485
|
-
newUniforms = {};
|
|
15486
16089
|
}
|
|
15487
16090
|
return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
|
|
15488
16091
|
});
|
|
@@ -15550,15 +16153,17 @@ function isSameThreeType(a, b) {
|
|
|
15550
16153
|
}
|
|
15551
16154
|
|
|
15552
16155
|
const isUniformNode = (value) => value !== null && typeof value === "object" && "value" in value && "uuid" in value;
|
|
16156
|
+
const isTSLNode$1 = (value) => value !== null && typeof value === "object" && "uuid" in value && "nodeType" in value;
|
|
15553
16157
|
function useUniform(name, value) {
|
|
15554
16158
|
const store = useStore();
|
|
16159
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
15555
16160
|
return React.useMemo(() => {
|
|
15556
16161
|
const state = store.getState();
|
|
15557
16162
|
const set = store.setState;
|
|
15558
16163
|
const existing = state.uniforms[name];
|
|
15559
16164
|
if (existing && isUniformNode(existing)) {
|
|
15560
|
-
if (value !== void 0) {
|
|
15561
|
-
existing.value = value;
|
|
16165
|
+
if (value !== void 0 && !isTSLNode$1(value) && !isUniformNode(value)) {
|
|
16166
|
+
existing.value = typeof value === "string" ? new webgpu.Color(value) : value;
|
|
15562
16167
|
}
|
|
15563
16168
|
return existing;
|
|
15564
16169
|
}
|
|
@@ -15567,7 +16172,24 @@ function useUniform(name, value) {
|
|
|
15567
16172
|
`[useUniform] Uniform "${name}" not found. Create it first with: useUniform('${name}', initialValue)`
|
|
15568
16173
|
);
|
|
15569
16174
|
}
|
|
15570
|
-
|
|
16175
|
+
if (isUniformNode(value)) {
|
|
16176
|
+
const node2 = value;
|
|
16177
|
+
if (typeof node2.setName === "function") {
|
|
16178
|
+
node2.setName(name);
|
|
16179
|
+
}
|
|
16180
|
+
set((s) => ({
|
|
16181
|
+
uniforms: { ...s.uniforms, [name]: node2 }
|
|
16182
|
+
}));
|
|
16183
|
+
return node2;
|
|
16184
|
+
}
|
|
16185
|
+
let node;
|
|
16186
|
+
if (isTSLNode$1(value)) {
|
|
16187
|
+
node = tsl.uniform(value);
|
|
16188
|
+
} else if (typeof value === "string") {
|
|
16189
|
+
node = tsl.uniform(new webgpu.Color(value));
|
|
16190
|
+
} else {
|
|
16191
|
+
node = tsl.uniform(value);
|
|
16192
|
+
}
|
|
15571
16193
|
if (typeof node.setName === "function") {
|
|
15572
16194
|
node.setName(name);
|
|
15573
16195
|
}
|
|
@@ -15578,7 +16200,7 @@ function useUniform(name, value) {
|
|
|
15578
16200
|
}
|
|
15579
16201
|
}));
|
|
15580
16202
|
return node;
|
|
15581
|
-
}, [store, name]);
|
|
16203
|
+
}, [store, name, hmrVersion]);
|
|
15582
16204
|
}
|
|
15583
16205
|
|
|
15584
16206
|
const isTSLNode = (value) => value !== null && typeof value === "object" && ("uuid" in value || "nodeType" in value);
|
|
@@ -15642,6 +16264,9 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15642
16264
|
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
15643
16265
|
const storeNodes = useThree((s) => s.nodes);
|
|
15644
16266
|
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16267
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16268
|
+
const readerDep = isReader ? storeNodes : null;
|
|
16269
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
15645
16270
|
const nodes = React.useMemo(() => {
|
|
15646
16271
|
if (creatorOrScope === void 0) {
|
|
15647
16272
|
return storeNodes;
|
|
@@ -15654,11 +16279,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15654
16279
|
const state = store.getState();
|
|
15655
16280
|
const set = store.setState;
|
|
15656
16281
|
const creator = creatorOrScope;
|
|
15657
|
-
const wrappedState =
|
|
15658
|
-
...state,
|
|
15659
|
-
uniforms: createScopedStore(state.uniforms),
|
|
15660
|
-
nodes: createScopedStore(state.nodes)
|
|
15661
|
-
};
|
|
16282
|
+
const wrappedState = createLazyCreatorState(state);
|
|
15662
16283
|
const created = creator(wrappedState);
|
|
15663
16284
|
const result = {};
|
|
15664
16285
|
let hasNewNodes = false;
|
|
@@ -15668,7 +16289,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15668
16289
|
if (currentScope[name]) {
|
|
15669
16290
|
result[name] = currentScope[name];
|
|
15670
16291
|
} else {
|
|
15671
|
-
|
|
16292
|
+
node.setName?.(`${scope}.${name}`);
|
|
15672
16293
|
result[name] = node;
|
|
15673
16294
|
hasNewNodes = true;
|
|
15674
16295
|
}
|
|
@@ -15688,7 +16309,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15688
16309
|
if (existing && isTSLNode(existing)) {
|
|
15689
16310
|
result[name] = existing;
|
|
15690
16311
|
} else {
|
|
15691
|
-
|
|
16312
|
+
node.setName?.(name);
|
|
15692
16313
|
result[name] = node;
|
|
15693
16314
|
hasNewNodes = true;
|
|
15694
16315
|
}
|
|
@@ -15697,15 +16318,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15697
16318
|
set((s) => ({ nodes: { ...s.nodes, ...result } }));
|
|
15698
16319
|
}
|
|
15699
16320
|
return result;
|
|
15700
|
-
}, [
|
|
15701
|
-
store,
|
|
15702
|
-
typeof creatorOrScope === "string" ? creatorOrScope : scope,
|
|
15703
|
-
// Only include storeNodes in deps for reader modes to enable reactivity
|
|
15704
|
-
// Creator mode intentionally excludes it to avoid re-running creator on unrelated changes
|
|
15705
|
-
isReader ? storeNodes : null,
|
|
15706
|
-
// Include hmrVersion for creator modes to allow rebuildNodes() to bust the cache
|
|
15707
|
-
isReader ? null : hmrVersion
|
|
15708
|
-
]);
|
|
16321
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
15709
16322
|
return { ...nodes, removeNodes: removeNodes2, clearNodes, rebuildNodes };
|
|
15710
16323
|
}
|
|
15711
16324
|
function rebuildAllNodes(store, scope) {
|
|
@@ -15757,15 +16370,11 @@ function useLocalNodes(creator) {
|
|
|
15757
16370
|
const uniforms = useThree((s) => s.uniforms);
|
|
15758
16371
|
const nodes = useThree((s) => s.nodes);
|
|
15759
16372
|
const textures = useThree((s) => s.textures);
|
|
16373
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
15760
16374
|
return React.useMemo(() => {
|
|
15761
|
-
const
|
|
15762
|
-
const wrappedState = {
|
|
15763
|
-
...state,
|
|
15764
|
-
uniforms: createScopedStore(state.uniforms),
|
|
15765
|
-
nodes: createScopedStore(state.nodes)
|
|
15766
|
-
};
|
|
16375
|
+
const wrappedState = createLazyCreatorState(store.getState());
|
|
15767
16376
|
return creator(wrappedState);
|
|
15768
|
-
}, [store, creator, uniforms, nodes, textures]);
|
|
16377
|
+
}, [store, creator, uniforms, nodes, textures, hmrVersion]);
|
|
15769
16378
|
}
|
|
15770
16379
|
|
|
15771
16380
|
function usePostProcessing(mainCB, setupCB) {
|
|
@@ -15865,8 +16474,15 @@ extend(THREE);
|
|
|
15865
16474
|
|
|
15866
16475
|
exports.Block = Block;
|
|
15867
16476
|
exports.Canvas = Canvas;
|
|
16477
|
+
exports.Environment = Environment;
|
|
16478
|
+
exports.EnvironmentCube = EnvironmentCube;
|
|
16479
|
+
exports.EnvironmentMap = EnvironmentMap;
|
|
16480
|
+
exports.EnvironmentPortal = EnvironmentPortal;
|
|
15868
16481
|
exports.ErrorBoundary = ErrorBoundary;
|
|
16482
|
+
exports.FROM_REF = FROM_REF;
|
|
15869
16483
|
exports.IsObject = IsObject;
|
|
16484
|
+
exports.ONCE = ONCE;
|
|
16485
|
+
exports.Portal = Portal;
|
|
15870
16486
|
exports.R3F_BUILD_LEGACY = R3F_BUILD_LEGACY;
|
|
15871
16487
|
exports.R3F_BUILD_WEBGPU = R3F_BUILD_WEBGPU;
|
|
15872
16488
|
exports.REACT_INTERNAL_PROPS = REACT_INTERNAL_PROPS;
|
|
@@ -15902,34 +16518,45 @@ exports.events = createPointerEvents;
|
|
|
15902
16518
|
exports.extend = extend;
|
|
15903
16519
|
exports.findInitialRoot = findInitialRoot;
|
|
15904
16520
|
exports.flushSync = flushSync;
|
|
16521
|
+
exports.fromRef = fromRef;
|
|
15905
16522
|
exports.getInstanceProps = getInstanceProps;
|
|
16523
|
+
exports.getPrimary = getPrimary;
|
|
16524
|
+
exports.getPrimaryIds = getPrimaryIds;
|
|
15906
16525
|
exports.getRootState = getRootState;
|
|
15907
16526
|
exports.getScheduler = getScheduler;
|
|
15908
16527
|
exports.getUuidPrefix = getUuidPrefix;
|
|
15909
16528
|
exports.hasConstructor = hasConstructor;
|
|
16529
|
+
exports.hasPrimary = hasPrimary;
|
|
15910
16530
|
exports.invalidate = invalidate;
|
|
15911
16531
|
exports.invalidateInstance = invalidateInstance;
|
|
15912
16532
|
exports.is = is;
|
|
15913
16533
|
exports.isColorRepresentation = isColorRepresentation;
|
|
15914
16534
|
exports.isCopyable = isCopyable;
|
|
16535
|
+
exports.isFromRef = isFromRef;
|
|
15915
16536
|
exports.isObject3D = isObject3D;
|
|
16537
|
+
exports.isOnce = isOnce;
|
|
15916
16538
|
exports.isOrthographicCamera = isOrthographicCamera;
|
|
15917
16539
|
exports.isRef = isRef;
|
|
15918
16540
|
exports.isRenderer = isRenderer;
|
|
15919
16541
|
exports.isTexture = isTexture;
|
|
15920
16542
|
exports.isVectorLike = isVectorLike;
|
|
16543
|
+
exports.once = once;
|
|
15921
16544
|
exports.prepare = prepare;
|
|
16545
|
+
exports.presetsObj = presetsObj;
|
|
15922
16546
|
exports.rebuildAllNodes = rebuildAllNodes;
|
|
15923
16547
|
exports.rebuildAllUniforms = rebuildAllUniforms;
|
|
15924
16548
|
exports.reconciler = reconciler;
|
|
16549
|
+
exports.registerPrimary = registerPrimary;
|
|
15925
16550
|
exports.removeInteractivity = removeInteractivity;
|
|
15926
16551
|
exports.removeNodes = removeNodes;
|
|
15927
16552
|
exports.removeUniforms = removeUniforms;
|
|
15928
16553
|
exports.resolve = resolve;
|
|
15929
16554
|
exports.unmountComponentAtNode = unmountComponentAtNode;
|
|
16555
|
+
exports.unregisterPrimary = unregisterPrimary;
|
|
15930
16556
|
exports.updateCamera = updateCamera;
|
|
15931
16557
|
exports.updateFrustum = updateFrustum;
|
|
15932
16558
|
exports.useBridge = useBridge;
|
|
16559
|
+
exports.useEnvironment = useEnvironment;
|
|
15933
16560
|
exports.useFrame = useFrame;
|
|
15934
16561
|
exports.useGraph = useGraph;
|
|
15935
16562
|
exports.useInstanceHandle = useInstanceHandle;
|
|
@@ -15946,3 +16573,4 @@ exports.useTextures = useTextures;
|
|
|
15946
16573
|
exports.useThree = useThree;
|
|
15947
16574
|
exports.useUniform = useUniform;
|
|
15948
16575
|
exports.useUniforms = useUniforms;
|
|
16576
|
+
exports.waitForPrimary = waitForPrimary;
|