@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.mjs
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import * as webgpu from 'three/webgpu';
|
|
2
|
-
import { RenderTarget, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1,
|
|
2
|
+
import { RenderTarget, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, Scene, WebGLCubeRenderTarget, HalfFloatType, Color, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, CanvasTarget, Raycaster, OrthographicCamera, PerspectiveCamera, PCFSoftShadowMap, VSMShadowMap, PCFShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGPURenderer, Vector4, PostProcessing } from 'three/webgpu';
|
|
3
3
|
import { Inspector } from 'three/addons/inspector/Inspector.js';
|
|
4
|
-
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
5
5
|
import * as React from 'react';
|
|
6
|
-
import React__default, {
|
|
6
|
+
import React__default, { useLayoutEffect, useRef, useMemo, useEffect, useContext, useImperativeHandle, useCallback, useState } from 'react';
|
|
7
7
|
import useMeasure from 'react-use-measure';
|
|
8
8
|
import { useFiber, useContextBridge, traverseFiber, FiberProvider } from 'its-fine';
|
|
9
|
+
import { useThree as useThree$1, useLoader as useLoader$1, useFrame as useFrame$1, createPortal as createPortal$1, applyProps as applyProps$1, extend as extend$1 } from '@react-three/fiber';
|
|
10
|
+
import { GroundedSkybox } from 'three/examples/jsm/objects/GroundedSkybox.js';
|
|
11
|
+
import { HDRLoader } from 'three/examples/jsm/loaders/HDRLoader.js';
|
|
12
|
+
import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';
|
|
13
|
+
import { UltraHDRLoader } from 'three/examples/jsm/loaders/UltraHDRLoader.js';
|
|
14
|
+
import { GainMapLoader } from '@monogrid/gainmap-js';
|
|
9
15
|
import Tb, { unstable_scheduleCallback, unstable_IdlePriority } from 'scheduler';
|
|
10
16
|
import { createWithEqualityFn } from 'zustand/traditional';
|
|
11
17
|
import { suspend, preload, clear } from 'suspend-react';
|
|
@@ -46,6 +52,374 @@ const THREE = /*#__PURE__*/_mergeNamespaces({
|
|
|
46
52
|
WebGLRenderer: WebGLRenderer
|
|
47
53
|
}, [webgpu]);
|
|
48
54
|
|
|
55
|
+
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
56
|
+
const pendingSubscribers = /* @__PURE__ */ new Map();
|
|
57
|
+
function registerPrimary(id, renderer, store) {
|
|
58
|
+
if (primaryRegistry.has(id)) {
|
|
59
|
+
console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
|
|
60
|
+
}
|
|
61
|
+
const entry = { renderer, store };
|
|
62
|
+
primaryRegistry.set(id, entry);
|
|
63
|
+
const subscribers = pendingSubscribers.get(id);
|
|
64
|
+
if (subscribers) {
|
|
65
|
+
subscribers.forEach((callback) => callback(entry));
|
|
66
|
+
pendingSubscribers.delete(id);
|
|
67
|
+
}
|
|
68
|
+
return () => {
|
|
69
|
+
const currentEntry = primaryRegistry.get(id);
|
|
70
|
+
if (currentEntry?.renderer === renderer) {
|
|
71
|
+
primaryRegistry.delete(id);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function getPrimary(id) {
|
|
76
|
+
return primaryRegistry.get(id);
|
|
77
|
+
}
|
|
78
|
+
function waitForPrimary(id, timeout = 5e3) {
|
|
79
|
+
const existing = primaryRegistry.get(id);
|
|
80
|
+
if (existing) {
|
|
81
|
+
return Promise.resolve(existing);
|
|
82
|
+
}
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const timeoutId = setTimeout(() => {
|
|
85
|
+
const subscribers = pendingSubscribers.get(id);
|
|
86
|
+
if (subscribers) {
|
|
87
|
+
const index = subscribers.indexOf(callback);
|
|
88
|
+
if (index !== -1) subscribers.splice(index, 1);
|
|
89
|
+
if (subscribers.length === 0) pendingSubscribers.delete(id);
|
|
90
|
+
}
|
|
91
|
+
reject(new Error(`Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}"> is mounted.`));
|
|
92
|
+
}, timeout);
|
|
93
|
+
const callback = (entry) => {
|
|
94
|
+
clearTimeout(timeoutId);
|
|
95
|
+
resolve(entry);
|
|
96
|
+
};
|
|
97
|
+
if (!pendingSubscribers.has(id)) {
|
|
98
|
+
pendingSubscribers.set(id, []);
|
|
99
|
+
}
|
|
100
|
+
pendingSubscribers.get(id).push(callback);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function hasPrimary(id) {
|
|
104
|
+
return primaryRegistry.has(id);
|
|
105
|
+
}
|
|
106
|
+
function unregisterPrimary(id) {
|
|
107
|
+
primaryRegistry.delete(id);
|
|
108
|
+
}
|
|
109
|
+
function getPrimaryIds() {
|
|
110
|
+
return Array.from(primaryRegistry.keys());
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const presetsObj = {
|
|
114
|
+
apartment: "lebombo_1k.hdr",
|
|
115
|
+
city: "potsdamer_platz_1k.hdr",
|
|
116
|
+
dawn: "kiara_1_dawn_1k.hdr",
|
|
117
|
+
forest: "forest_slope_1k.hdr",
|
|
118
|
+
lobby: "st_fagans_interior_1k.hdr",
|
|
119
|
+
night: "dikhololo_night_1k.hdr",
|
|
120
|
+
park: "rooitou_park_1k.hdr",
|
|
121
|
+
studio: "studio_small_03_1k.hdr",
|
|
122
|
+
sunset: "venice_sunset_1k.hdr",
|
|
123
|
+
warehouse: "empty_warehouse_01_1k.hdr"
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
|
|
127
|
+
const isArray = (arr) => Array.isArray(arr);
|
|
128
|
+
const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
|
|
129
|
+
function useEnvironment({
|
|
130
|
+
files = defaultFiles,
|
|
131
|
+
path = "",
|
|
132
|
+
preset = void 0,
|
|
133
|
+
colorSpace = void 0,
|
|
134
|
+
extensions
|
|
135
|
+
} = {}) {
|
|
136
|
+
if (preset) {
|
|
137
|
+
validatePreset(preset);
|
|
138
|
+
files = presetsObj[preset];
|
|
139
|
+
path = CUBEMAP_ROOT;
|
|
140
|
+
}
|
|
141
|
+
const multiFile = isArray(files);
|
|
142
|
+
const { extension, isCubemap } = getExtension(files);
|
|
143
|
+
const loader = getLoader$1(extension);
|
|
144
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
145
|
+
const renderer = useThree$1((state) => state.renderer);
|
|
146
|
+
useLayoutEffect(() => {
|
|
147
|
+
if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
|
|
148
|
+
function clearGainmapTexture() {
|
|
149
|
+
useLoader$1.clear(loader, multiFile ? [files] : files);
|
|
150
|
+
}
|
|
151
|
+
renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
|
|
152
|
+
}, [files, renderer.domElement]);
|
|
153
|
+
const loaderResult = useLoader$1(
|
|
154
|
+
loader,
|
|
155
|
+
multiFile ? [files] : files,
|
|
156
|
+
(loader2) => {
|
|
157
|
+
if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
|
|
158
|
+
loader2.setRenderer?.(renderer);
|
|
159
|
+
}
|
|
160
|
+
loader2.setPath?.(path);
|
|
161
|
+
if (extensions) extensions(loader2);
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
let texture = multiFile ? (
|
|
165
|
+
// @ts-ignore
|
|
166
|
+
loaderResult[0]
|
|
167
|
+
) : loaderResult;
|
|
168
|
+
if (extension === "jpg" || extension === "jpeg" || extension === "webp") {
|
|
169
|
+
texture = texture.renderTarget?.texture;
|
|
170
|
+
}
|
|
171
|
+
texture.mapping = isCubemap ? CubeReflectionMapping : EquirectangularReflectionMapping;
|
|
172
|
+
texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
|
|
173
|
+
return texture;
|
|
174
|
+
}
|
|
175
|
+
const preloadDefaultOptions = {
|
|
176
|
+
files: defaultFiles,
|
|
177
|
+
path: "",
|
|
178
|
+
preset: void 0,
|
|
179
|
+
extensions: void 0
|
|
180
|
+
};
|
|
181
|
+
useEnvironment.preload = (preloadOptions) => {
|
|
182
|
+
const options = { ...preloadDefaultOptions, ...preloadOptions };
|
|
183
|
+
let { files, path = "" } = options;
|
|
184
|
+
const { preset, extensions } = options;
|
|
185
|
+
if (preset) {
|
|
186
|
+
validatePreset(preset);
|
|
187
|
+
files = presetsObj[preset];
|
|
188
|
+
path = CUBEMAP_ROOT;
|
|
189
|
+
}
|
|
190
|
+
const { extension } = getExtension(files);
|
|
191
|
+
if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
|
|
192
|
+
throw new Error("useEnvironment: Preloading gainmaps is not supported");
|
|
193
|
+
}
|
|
194
|
+
const loader = getLoader$1(extension);
|
|
195
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
196
|
+
useLoader$1.preload(loader, isArray(files) ? [files] : files, (loader2) => {
|
|
197
|
+
loader2.setPath?.(path);
|
|
198
|
+
if (extensions) extensions(loader2);
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
const clearDefaultOptins = {
|
|
202
|
+
files: defaultFiles,
|
|
203
|
+
preset: void 0
|
|
204
|
+
};
|
|
205
|
+
useEnvironment.clear = (clearOptions) => {
|
|
206
|
+
const options = { ...clearDefaultOptins, ...clearOptions };
|
|
207
|
+
let { files } = options;
|
|
208
|
+
const { preset } = options;
|
|
209
|
+
if (preset) {
|
|
210
|
+
validatePreset(preset);
|
|
211
|
+
files = presetsObj[preset];
|
|
212
|
+
}
|
|
213
|
+
const { extension } = getExtension(files);
|
|
214
|
+
const loader = getLoader$1(extension);
|
|
215
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
216
|
+
useLoader$1.clear(loader, isArray(files) ? [files] : files);
|
|
217
|
+
};
|
|
218
|
+
function validatePreset(preset) {
|
|
219
|
+
if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
|
|
220
|
+
}
|
|
221
|
+
function getExtension(files) {
|
|
222
|
+
const isCubemap = isArray(files) && files.length === 6;
|
|
223
|
+
const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
|
|
224
|
+
const firstEntry = isArray(files) ? files[0] : files;
|
|
225
|
+
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();
|
|
226
|
+
return { extension, isCubemap, isGainmap };
|
|
227
|
+
}
|
|
228
|
+
function getLoader$1(extension) {
|
|
229
|
+
const loader = extension === "cube" ? CubeTextureLoader : extension === "hdr" ? HDRLoader : extension === "exr" ? EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader : extension === "webp" ? GainMapLoader : null;
|
|
230
|
+
return loader;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const isRef$1 = (obj) => obj.current && obj.current.isScene;
|
|
234
|
+
const resolveScene = (scene) => isRef$1(scene) ? scene.current : scene;
|
|
235
|
+
function setEnvProps(background, scene, defaultScene, texture, sceneProps = {}) {
|
|
236
|
+
sceneProps = {
|
|
237
|
+
backgroundBlurriness: 0,
|
|
238
|
+
backgroundIntensity: 1,
|
|
239
|
+
backgroundRotation: [0, 0, 0],
|
|
240
|
+
environmentIntensity: 1,
|
|
241
|
+
environmentRotation: [0, 0, 0],
|
|
242
|
+
...sceneProps
|
|
243
|
+
};
|
|
244
|
+
const target = resolveScene(scene || defaultScene);
|
|
245
|
+
const oldbg = target.background;
|
|
246
|
+
const oldenv = target.environment;
|
|
247
|
+
const oldSceneProps = {
|
|
248
|
+
// @ts-ignore
|
|
249
|
+
backgroundBlurriness: target.backgroundBlurriness,
|
|
250
|
+
// @ts-ignore
|
|
251
|
+
backgroundIntensity: target.backgroundIntensity,
|
|
252
|
+
// @ts-ignore
|
|
253
|
+
backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
|
|
254
|
+
// @ts-ignore
|
|
255
|
+
environmentIntensity: target.environmentIntensity,
|
|
256
|
+
// @ts-ignore
|
|
257
|
+
environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
|
|
258
|
+
};
|
|
259
|
+
if (background !== "only") target.environment = texture;
|
|
260
|
+
if (background) target.background = texture;
|
|
261
|
+
applyProps$1(target, sceneProps);
|
|
262
|
+
return () => {
|
|
263
|
+
if (background !== "only") target.environment = oldenv;
|
|
264
|
+
if (background) target.background = oldbg;
|
|
265
|
+
applyProps$1(target, oldSceneProps);
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function EnvironmentMap({ scene, background = false, map, ...config }) {
|
|
269
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
270
|
+
React.useLayoutEffect(() => {
|
|
271
|
+
if (map) return setEnvProps(background, scene, defaultScene, map, config);
|
|
272
|
+
});
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
function EnvironmentCube({
|
|
276
|
+
background = false,
|
|
277
|
+
scene,
|
|
278
|
+
blur,
|
|
279
|
+
backgroundBlurriness,
|
|
280
|
+
backgroundIntensity,
|
|
281
|
+
backgroundRotation,
|
|
282
|
+
environmentIntensity,
|
|
283
|
+
environmentRotation,
|
|
284
|
+
...rest
|
|
285
|
+
}) {
|
|
286
|
+
const texture = useEnvironment(rest);
|
|
287
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
288
|
+
React.useLayoutEffect(() => {
|
|
289
|
+
return setEnvProps(background, scene, defaultScene, texture, {
|
|
290
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
291
|
+
backgroundIntensity,
|
|
292
|
+
backgroundRotation,
|
|
293
|
+
environmentIntensity,
|
|
294
|
+
environmentRotation
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
React.useEffect(() => {
|
|
298
|
+
return () => {
|
|
299
|
+
texture.dispose();
|
|
300
|
+
};
|
|
301
|
+
}, [texture]);
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
function EnvironmentPortal({
|
|
305
|
+
children,
|
|
306
|
+
near = 0.1,
|
|
307
|
+
far = 1e3,
|
|
308
|
+
resolution = 256,
|
|
309
|
+
frames = 1,
|
|
310
|
+
map,
|
|
311
|
+
background = false,
|
|
312
|
+
blur,
|
|
313
|
+
backgroundBlurriness,
|
|
314
|
+
backgroundIntensity,
|
|
315
|
+
backgroundRotation,
|
|
316
|
+
environmentIntensity,
|
|
317
|
+
environmentRotation,
|
|
318
|
+
scene,
|
|
319
|
+
files,
|
|
320
|
+
path,
|
|
321
|
+
preset = void 0,
|
|
322
|
+
extensions
|
|
323
|
+
}) {
|
|
324
|
+
const gl = useThree$1((state) => state.gl);
|
|
325
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
326
|
+
const camera = React.useRef(null);
|
|
327
|
+
const [virtualScene] = React.useState(() => new Scene());
|
|
328
|
+
const fbo = React.useMemo(() => {
|
|
329
|
+
const fbo2 = new WebGLCubeRenderTarget(resolution);
|
|
330
|
+
fbo2.texture.type = HalfFloatType;
|
|
331
|
+
return fbo2;
|
|
332
|
+
}, [resolution]);
|
|
333
|
+
React.useEffect(() => {
|
|
334
|
+
return () => {
|
|
335
|
+
fbo.dispose();
|
|
336
|
+
};
|
|
337
|
+
}, [fbo]);
|
|
338
|
+
React.useLayoutEffect(() => {
|
|
339
|
+
if (frames === 1) {
|
|
340
|
+
const autoClear = gl.autoClear;
|
|
341
|
+
gl.autoClear = true;
|
|
342
|
+
camera.current.update(gl, virtualScene);
|
|
343
|
+
gl.autoClear = autoClear;
|
|
344
|
+
}
|
|
345
|
+
return setEnvProps(background, scene, defaultScene, fbo.texture, {
|
|
346
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
347
|
+
backgroundIntensity,
|
|
348
|
+
backgroundRotation,
|
|
349
|
+
environmentIntensity,
|
|
350
|
+
environmentRotation
|
|
351
|
+
});
|
|
352
|
+
}, [children, virtualScene, fbo.texture, scene, defaultScene, background, frames, gl]);
|
|
353
|
+
let count = 1;
|
|
354
|
+
useFrame$1(() => {
|
|
355
|
+
if (frames === Infinity || count < frames) {
|
|
356
|
+
const autoClear = gl.autoClear;
|
|
357
|
+
gl.autoClear = true;
|
|
358
|
+
camera.current.update(gl, virtualScene);
|
|
359
|
+
gl.autoClear = autoClear;
|
|
360
|
+
count++;
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
return /* @__PURE__ */ jsx(Fragment, { children: createPortal$1(
|
|
364
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
365
|
+
children,
|
|
366
|
+
/* @__PURE__ */ jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
|
|
367
|
+
files || preset ? /* @__PURE__ */ jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsx(EnvironmentMap, { background: true, map, extensions }) : null
|
|
368
|
+
] }),
|
|
369
|
+
virtualScene
|
|
370
|
+
) });
|
|
371
|
+
}
|
|
372
|
+
function EnvironmentGround(props) {
|
|
373
|
+
const textureDefault = useEnvironment(props);
|
|
374
|
+
const texture = props.map || textureDefault;
|
|
375
|
+
React.useMemo(() => extend$1({ GroundProjectedEnvImpl: GroundedSkybox }), []);
|
|
376
|
+
React.useEffect(() => {
|
|
377
|
+
return () => {
|
|
378
|
+
textureDefault.dispose();
|
|
379
|
+
};
|
|
380
|
+
}, [textureDefault]);
|
|
381
|
+
const height = props.ground?.height ?? 15;
|
|
382
|
+
const radius = props.ground?.radius ?? 60;
|
|
383
|
+
const scale = props.ground?.scale ?? 1e3;
|
|
384
|
+
const args = React.useMemo(
|
|
385
|
+
() => [texture, height, radius],
|
|
386
|
+
[texture, height, radius]
|
|
387
|
+
);
|
|
388
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
389
|
+
/* @__PURE__ */ jsx(EnvironmentMap, { ...props, map: texture }),
|
|
390
|
+
/* @__PURE__ */ jsx("groundProjectedEnvImpl", { args, scale })
|
|
391
|
+
] });
|
|
392
|
+
}
|
|
393
|
+
function EnvironmentColor({ color, scene }) {
|
|
394
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
395
|
+
React.useLayoutEffect(() => {
|
|
396
|
+
if (color === void 0) return;
|
|
397
|
+
const target = resolveScene(scene || defaultScene);
|
|
398
|
+
const oldBg = target.background;
|
|
399
|
+
target.background = new Color(color);
|
|
400
|
+
return () => {
|
|
401
|
+
target.background = oldBg;
|
|
402
|
+
};
|
|
403
|
+
});
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
function EnvironmentDualSource(props) {
|
|
407
|
+
const { backgroundFiles, ...envProps } = props;
|
|
408
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
409
|
+
/* @__PURE__ */ jsx(EnvironmentCube, { ...envProps, background: false }),
|
|
410
|
+
/* @__PURE__ */ jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
|
|
411
|
+
] });
|
|
412
|
+
}
|
|
413
|
+
function Environment(props) {
|
|
414
|
+
if (props.color && !props.files && !props.preset && !props.map) {
|
|
415
|
+
return /* @__PURE__ */ jsx(EnvironmentColor, { ...props });
|
|
416
|
+
}
|
|
417
|
+
if (props.backgroundFiles && props.backgroundFiles !== props.files) {
|
|
418
|
+
return /* @__PURE__ */ jsx(EnvironmentDualSource, { ...props });
|
|
419
|
+
}
|
|
420
|
+
return props.ground ? /* @__PURE__ */ jsx(EnvironmentGround, { ...props }) : props.map ? /* @__PURE__ */ jsx(EnvironmentMap, { ...props }) : props.children ? /* @__PURE__ */ jsx(EnvironmentPortal, { ...props }) : /* @__PURE__ */ jsx(EnvironmentCube, { ...props });
|
|
421
|
+
}
|
|
422
|
+
|
|
49
423
|
var __defProp$3 = Object.defineProperty;
|
|
50
424
|
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
51
425
|
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -225,7 +599,8 @@ function prepare(target, root, type, props) {
|
|
|
225
599
|
object,
|
|
226
600
|
eventCount: 0,
|
|
227
601
|
handlers: {},
|
|
228
|
-
isHidden: false
|
|
602
|
+
isHidden: false,
|
|
603
|
+
deferredRefs: []
|
|
229
604
|
};
|
|
230
605
|
if (object) object.__r3f = instance;
|
|
231
606
|
}
|
|
@@ -274,7 +649,7 @@ function createOcclusionObserverNode(store, uniform) {
|
|
|
274
649
|
let occlusionSetupPromise = null;
|
|
275
650
|
function enableOcclusion(store) {
|
|
276
651
|
const state = store.getState();
|
|
277
|
-
const { internal, renderer
|
|
652
|
+
const { internal, renderer } = state;
|
|
278
653
|
if (internal.occlusionEnabled || occlusionSetupPromise) return;
|
|
279
654
|
const hasOcclusionSupport = typeof renderer?.isOccluded === "function";
|
|
280
655
|
if (!hasOcclusionSupport) {
|
|
@@ -437,6 +812,22 @@ function hasVisibilityHandlers(handlers) {
|
|
|
437
812
|
return !!(handlers.onFramed || handlers.onOccluded || handlers.onVisible);
|
|
438
813
|
}
|
|
439
814
|
|
|
815
|
+
const FROM_REF = Symbol.for("@react-three/fiber.fromRef");
|
|
816
|
+
function fromRef(ref) {
|
|
817
|
+
return { [FROM_REF]: ref };
|
|
818
|
+
}
|
|
819
|
+
function isFromRef(value) {
|
|
820
|
+
return value !== null && typeof value === "object" && FROM_REF in value;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
const ONCE = Symbol.for("@react-three/fiber.once");
|
|
824
|
+
function once(...args) {
|
|
825
|
+
return { [ONCE]: args.length ? args : true };
|
|
826
|
+
}
|
|
827
|
+
function isOnce(value) {
|
|
828
|
+
return value !== null && typeof value === "object" && ONCE in value;
|
|
829
|
+
}
|
|
830
|
+
|
|
440
831
|
const RESERVED_PROPS = [
|
|
441
832
|
"children",
|
|
442
833
|
"key",
|
|
@@ -507,7 +898,7 @@ function getMemoizedPrototype(root) {
|
|
|
507
898
|
ctor = new root.constructor();
|
|
508
899
|
MEMOIZED_PROTOTYPES.set(root.constructor, ctor);
|
|
509
900
|
}
|
|
510
|
-
} catch
|
|
901
|
+
} catch {
|
|
511
902
|
}
|
|
512
903
|
return ctor;
|
|
513
904
|
}
|
|
@@ -553,6 +944,25 @@ function applyProps(object, props) {
|
|
|
553
944
|
continue;
|
|
554
945
|
}
|
|
555
946
|
if (value === void 0) continue;
|
|
947
|
+
if (isFromRef(value)) {
|
|
948
|
+
instance?.deferredRefs?.push({ prop, ref: value[FROM_REF] });
|
|
949
|
+
continue;
|
|
950
|
+
}
|
|
951
|
+
if (isOnce(value)) {
|
|
952
|
+
if (instance?.appliedOnce?.has(prop)) continue;
|
|
953
|
+
if (instance) {
|
|
954
|
+
instance.appliedOnce ?? (instance.appliedOnce = /* @__PURE__ */ new Set());
|
|
955
|
+
instance.appliedOnce.add(prop);
|
|
956
|
+
}
|
|
957
|
+
const { root: targetRoot, key: targetKey } = resolve(object, prop);
|
|
958
|
+
const args = value[ONCE];
|
|
959
|
+
if (typeof targetRoot[targetKey] === "function") {
|
|
960
|
+
targetRoot[targetKey](...args === true ? [] : args);
|
|
961
|
+
} else if (args !== true && args.length > 0) {
|
|
962
|
+
targetRoot[targetKey] = args[0];
|
|
963
|
+
}
|
|
964
|
+
continue;
|
|
965
|
+
}
|
|
556
966
|
let { root, key, target } = resolve(object, prop);
|
|
557
967
|
if (target === void 0 && (typeof root !== "object" || root === null)) {
|
|
558
968
|
throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`);
|
|
@@ -575,7 +985,7 @@ function applyProps(object, props) {
|
|
|
575
985
|
else target.set(value);
|
|
576
986
|
} else {
|
|
577
987
|
root[key] = value;
|
|
578
|
-
if (rootState &&
|
|
988
|
+
if (rootState && rootState.renderer?.outputColorSpace === SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
579
989
|
root[key].format === RGBAFormat && root[key].type === UnsignedByteType) {
|
|
580
990
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
581
991
|
}
|
|
@@ -932,7 +1342,7 @@ function createPointerEvents(store) {
|
|
|
932
1342
|
return {
|
|
933
1343
|
priority: 1,
|
|
934
1344
|
enabled: true,
|
|
935
|
-
compute(event, state
|
|
1345
|
+
compute(event, state) {
|
|
936
1346
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
937
1347
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
938
1348
|
},
|
|
@@ -1030,331 +1440,26 @@ function notifyAlpha({ message, link }) {
|
|
|
1030
1440
|
}
|
|
1031
1441
|
}
|
|
1032
1442
|
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
let performanceTimeout = void 0;
|
|
1056
|
-
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
1057
|
-
const pointer = new Vector2();
|
|
1058
|
-
const rootState = {
|
|
1059
|
-
set,
|
|
1060
|
-
get,
|
|
1061
|
-
// Mock objects that have to be configured
|
|
1062
|
-
gl: null,
|
|
1063
|
-
renderer: null,
|
|
1064
|
-
camera: null,
|
|
1065
|
-
frustum: new Frustum(),
|
|
1066
|
-
autoUpdateFrustum: true,
|
|
1067
|
-
raycaster: null,
|
|
1068
|
-
events: { priority: 1, enabled: true, connected: false },
|
|
1069
|
-
scene: null,
|
|
1070
|
-
rootScene: null,
|
|
1071
|
-
xr: null,
|
|
1072
|
-
inspector: null,
|
|
1073
|
-
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
1074
|
-
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
1075
|
-
legacy: false,
|
|
1076
|
-
linear: false,
|
|
1077
|
-
flat: false,
|
|
1078
|
-
textureColorSpace: "srgb",
|
|
1079
|
-
isLegacy: false,
|
|
1080
|
-
webGPUSupported: false,
|
|
1081
|
-
isNative: false,
|
|
1082
|
-
controls: null,
|
|
1083
|
-
pointer,
|
|
1084
|
-
mouse: pointer,
|
|
1085
|
-
frameloop: "always",
|
|
1086
|
-
onPointerMissed: void 0,
|
|
1087
|
-
onDragOverMissed: void 0,
|
|
1088
|
-
onDropMissed: void 0,
|
|
1089
|
-
performance: {
|
|
1090
|
-
current: 1,
|
|
1091
|
-
min: 0.5,
|
|
1092
|
-
max: 1,
|
|
1093
|
-
debounce: 200,
|
|
1094
|
-
regress: () => {
|
|
1095
|
-
const state2 = get();
|
|
1096
|
-
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
1097
|
-
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
1098
|
-
performanceTimeout = setTimeout(
|
|
1099
|
-
() => setPerformanceCurrent(get().performance.max),
|
|
1100
|
-
state2.performance.debounce
|
|
1101
|
-
);
|
|
1102
|
-
}
|
|
1103
|
-
},
|
|
1104
|
-
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
1105
|
-
viewport: {
|
|
1106
|
-
initialDpr: 0,
|
|
1107
|
-
dpr: 0,
|
|
1108
|
-
width: 0,
|
|
1109
|
-
height: 0,
|
|
1110
|
-
top: 0,
|
|
1111
|
-
left: 0,
|
|
1112
|
-
aspect: 0,
|
|
1113
|
-
distance: 0,
|
|
1114
|
-
factor: 0,
|
|
1115
|
-
getCurrentViewport
|
|
1116
|
-
},
|
|
1117
|
-
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
1118
|
-
setSize: (width, height, top, left) => {
|
|
1119
|
-
const state2 = get();
|
|
1120
|
-
if (width === void 0) {
|
|
1121
|
-
set({ _sizeImperative: false });
|
|
1122
|
-
if (state2._sizeProps) {
|
|
1123
|
-
const { width: propW, height: propH } = state2._sizeProps;
|
|
1124
|
-
if (propW !== void 0 || propH !== void 0) {
|
|
1125
|
-
const currentSize = state2.size;
|
|
1126
|
-
const newSize = {
|
|
1127
|
-
width: propW ?? currentSize.width,
|
|
1128
|
-
height: propH ?? currentSize.height,
|
|
1129
|
-
top: currentSize.top,
|
|
1130
|
-
left: currentSize.left
|
|
1131
|
-
};
|
|
1132
|
-
set((s) => ({
|
|
1133
|
-
size: newSize,
|
|
1134
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
1135
|
-
}));
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
return;
|
|
1139
|
-
}
|
|
1140
|
-
const w = width;
|
|
1141
|
-
const h = height ?? width;
|
|
1142
|
-
const t = top ?? state2.size.top;
|
|
1143
|
-
const l = left ?? state2.size.left;
|
|
1144
|
-
const size = { width: w, height: h, top: t, left: l };
|
|
1145
|
-
set((s) => ({
|
|
1146
|
-
size,
|
|
1147
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
1148
|
-
_sizeImperative: true
|
|
1149
|
-
}));
|
|
1150
|
-
},
|
|
1151
|
-
setDpr: (dpr) => set((state2) => {
|
|
1152
|
-
const resolved = calculateDpr(dpr);
|
|
1153
|
-
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
1154
|
-
}),
|
|
1155
|
-
setFrameloop: (frameloop = "always") => {
|
|
1156
|
-
set(() => ({ frameloop }));
|
|
1157
|
-
},
|
|
1158
|
-
setError: (error) => set(() => ({ error })),
|
|
1159
|
-
error: null,
|
|
1160
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
|
|
1161
|
-
uniforms: {},
|
|
1162
|
-
nodes: {},
|
|
1163
|
-
textures: /* @__PURE__ */ new Map(),
|
|
1164
|
-
postProcessing: null,
|
|
1165
|
-
passes: {},
|
|
1166
|
-
_hmrVersion: 0,
|
|
1167
|
-
_sizeImperative: false,
|
|
1168
|
-
_sizeProps: null,
|
|
1169
|
-
previousRoot: void 0,
|
|
1170
|
-
internal: {
|
|
1171
|
-
// Events
|
|
1172
|
-
interaction: [],
|
|
1173
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
1174
|
-
subscribers: [],
|
|
1175
|
-
initialClick: [0, 0],
|
|
1176
|
-
initialHits: [],
|
|
1177
|
-
capturedMap: /* @__PURE__ */ new Map(),
|
|
1178
|
-
lastEvent: React.createRef(),
|
|
1179
|
-
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
1180
|
-
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
1181
|
-
// Occlusion system (WebGPU only)
|
|
1182
|
-
occlusionEnabled: false,
|
|
1183
|
-
occlusionObserver: null,
|
|
1184
|
-
occlusionCache: /* @__PURE__ */ new Map(),
|
|
1185
|
-
helperGroup: null,
|
|
1186
|
-
// Updates
|
|
1187
|
-
active: false,
|
|
1188
|
-
frames: 0,
|
|
1189
|
-
priority: 0,
|
|
1190
|
-
subscribe: (ref, priority, store) => {
|
|
1191
|
-
const internal = get().internal;
|
|
1192
|
-
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1193
|
-
internal.subscribers.push({ ref, priority, store });
|
|
1194
|
-
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
1195
|
-
return () => {
|
|
1196
|
-
const internal2 = get().internal;
|
|
1197
|
-
if (internal2?.subscribers) {
|
|
1198
|
-
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
1199
|
-
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
1200
|
-
}
|
|
1201
|
-
};
|
|
1202
|
-
},
|
|
1203
|
-
// Renderer Storage (single source of truth)
|
|
1204
|
-
actualRenderer: null,
|
|
1205
|
-
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
1206
|
-
scheduler: null
|
|
1207
|
-
}
|
|
1208
|
-
};
|
|
1209
|
-
return rootState;
|
|
1210
|
-
});
|
|
1211
|
-
const state = rootStore.getState();
|
|
1212
|
-
Object.defineProperty(state, "gl", {
|
|
1213
|
-
get() {
|
|
1214
|
-
const currentState = rootStore.getState();
|
|
1215
|
-
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
1216
|
-
const stack = new Error().stack || "";
|
|
1217
|
-
const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
|
|
1218
|
-
if (!isInternalAccess) {
|
|
1219
|
-
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
1220
|
-
notifyDepreciated({
|
|
1221
|
-
heading: "Accessing state.gl in WebGPU mode",
|
|
1222
|
-
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
|
|
1223
|
-
});
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
return currentState.internal.actualRenderer;
|
|
1227
|
-
},
|
|
1228
|
-
set(value) {
|
|
1229
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1230
|
-
},
|
|
1231
|
-
enumerable: true,
|
|
1232
|
-
configurable: true
|
|
1233
|
-
});
|
|
1234
|
-
Object.defineProperty(state, "renderer", {
|
|
1235
|
-
get() {
|
|
1236
|
-
return rootStore.getState().internal.actualRenderer;
|
|
1237
|
-
},
|
|
1238
|
-
set(value) {
|
|
1239
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1240
|
-
},
|
|
1241
|
-
enumerable: true,
|
|
1242
|
-
configurable: true
|
|
1243
|
-
});
|
|
1244
|
-
let oldScene = state.scene;
|
|
1245
|
-
rootStore.subscribe(() => {
|
|
1246
|
-
const currentState = rootStore.getState();
|
|
1247
|
-
const { scene, rootScene, set } = currentState;
|
|
1248
|
-
if (scene !== oldScene) {
|
|
1249
|
-
oldScene = scene;
|
|
1250
|
-
if (scene?.isScene && scene !== rootScene) {
|
|
1251
|
-
set({ rootScene: scene });
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
});
|
|
1255
|
-
let oldSize = state.size;
|
|
1256
|
-
let oldDpr = state.viewport.dpr;
|
|
1257
|
-
let oldCamera = state.camera;
|
|
1258
|
-
rootStore.subscribe(() => {
|
|
1259
|
-
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
1260
|
-
const actualRenderer = internal.actualRenderer;
|
|
1261
|
-
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
1262
|
-
oldSize = size;
|
|
1263
|
-
oldDpr = viewport.dpr;
|
|
1264
|
-
updateCamera(camera, size);
|
|
1265
|
-
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
1266
|
-
const updateStyle = typeof HTMLCanvasElement !== "undefined" && actualRenderer.domElement instanceof HTMLCanvasElement;
|
|
1267
|
-
actualRenderer.setSize(size.width, size.height, updateStyle);
|
|
1268
|
-
}
|
|
1269
|
-
if (camera !== oldCamera) {
|
|
1270
|
-
oldCamera = camera;
|
|
1271
|
-
const { rootScene } = rootStore.getState();
|
|
1272
|
-
if (camera && rootScene && !camera.parent) {
|
|
1273
|
-
rootScene.add(camera);
|
|
1274
|
-
}
|
|
1275
|
-
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
1276
|
-
const currentState = rootStore.getState();
|
|
1277
|
-
if (currentState.autoUpdateFrustum && camera) {
|
|
1278
|
-
updateFrustum(camera, currentState.frustum);
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
});
|
|
1282
|
-
rootStore.subscribe((state2) => invalidate(state2));
|
|
1283
|
-
return rootStore;
|
|
1284
|
-
};
|
|
1285
|
-
|
|
1286
|
-
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
1287
|
-
const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
1288
|
-
function getLoader(Proto) {
|
|
1289
|
-
if (isConstructor$1(Proto)) {
|
|
1290
|
-
let loader = memoizedLoaders.get(Proto);
|
|
1291
|
-
if (!loader) {
|
|
1292
|
-
loader = new Proto();
|
|
1293
|
-
memoizedLoaders.set(Proto, loader);
|
|
1294
|
-
}
|
|
1295
|
-
return loader;
|
|
1296
|
-
}
|
|
1297
|
-
return Proto;
|
|
1298
|
-
}
|
|
1299
|
-
function loadingFn(extensions, onProgress) {
|
|
1300
|
-
return function(Proto, input) {
|
|
1301
|
-
const loader = getLoader(Proto);
|
|
1302
|
-
if (extensions) extensions(loader);
|
|
1303
|
-
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
1304
|
-
return loader.loadAsync(input, onProgress).then((data) => {
|
|
1305
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
1306
|
-
return data;
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
|
-
return new Promise(
|
|
1310
|
-
(res, reject) => loader.load(
|
|
1311
|
-
input,
|
|
1312
|
-
(data) => {
|
|
1313
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
1314
|
-
res(data);
|
|
1315
|
-
},
|
|
1316
|
-
onProgress,
|
|
1317
|
-
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
1318
|
-
)
|
|
1319
|
-
);
|
|
1320
|
-
};
|
|
1321
|
-
}
|
|
1322
|
-
function useLoader(loader, input, extensions, onProgress) {
|
|
1323
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1324
|
-
const fn = loadingFn(extensions, onProgress);
|
|
1325
|
-
const results = keys.map((key) => suspend(fn, [loader, key], { equal: is.equ }));
|
|
1326
|
-
return Array.isArray(input) ? results : results[0];
|
|
1327
|
-
}
|
|
1328
|
-
useLoader.preload = function(loader, input, extensions, onProgress) {
|
|
1329
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1330
|
-
keys.forEach((key) => preload(loadingFn(extensions, onProgress), [loader, key]));
|
|
1331
|
-
};
|
|
1332
|
-
useLoader.clear = function(loader, input) {
|
|
1333
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1334
|
-
keys.forEach((key) => clear([loader, key]));
|
|
1335
|
-
};
|
|
1336
|
-
useLoader.loader = getLoader;
|
|
1337
|
-
|
|
1338
|
-
var __defProp$2 = Object.defineProperty;
|
|
1339
|
-
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1340
|
-
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1341
|
-
const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
|
|
1342
|
-
class PhaseGraph {
|
|
1343
|
-
constructor() {
|
|
1344
|
-
/** Ordered list of phase nodes */
|
|
1345
|
-
__publicField$2(this, "phases", []);
|
|
1346
|
-
/** Quick lookup by name */
|
|
1347
|
-
__publicField$2(this, "phaseMap", /* @__PURE__ */ new Map());
|
|
1348
|
-
/** Cached ordered names (invalidated on changes) */
|
|
1349
|
-
__publicField$2(this, "orderedNamesCache", null);
|
|
1350
|
-
this.initializeDefaultPhases();
|
|
1351
|
-
}
|
|
1352
|
-
//* Initialization --------------------------------
|
|
1353
|
-
initializeDefaultPhases() {
|
|
1354
|
-
for (const name of DEFAULT_PHASES) {
|
|
1355
|
-
const node = { name, isAutoGenerated: false };
|
|
1356
|
-
this.phases.push(node);
|
|
1357
|
-
this.phaseMap.set(name, node);
|
|
1443
|
+
var __defProp$2 = Object.defineProperty;
|
|
1444
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1445
|
+
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1446
|
+
const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
|
|
1447
|
+
class PhaseGraph {
|
|
1448
|
+
constructor() {
|
|
1449
|
+
/** Ordered list of phase nodes */
|
|
1450
|
+
__publicField$2(this, "phases", []);
|
|
1451
|
+
/** Quick lookup by name */
|
|
1452
|
+
__publicField$2(this, "phaseMap", /* @__PURE__ */ new Map());
|
|
1453
|
+
/** Cached ordered names (invalidated on changes) */
|
|
1454
|
+
__publicField$2(this, "orderedNamesCache", null);
|
|
1455
|
+
this.initializeDefaultPhases();
|
|
1456
|
+
}
|
|
1457
|
+
//* Initialization --------------------------------
|
|
1458
|
+
initializeDefaultPhases() {
|
|
1459
|
+
for (const name of DEFAULT_PHASES) {
|
|
1460
|
+
const node = { name, isAutoGenerated: false };
|
|
1461
|
+
this.phases.push(node);
|
|
1462
|
+
this.phaseMap.set(name, node);
|
|
1358
1463
|
}
|
|
1359
1464
|
this.invalidateCache();
|
|
1360
1465
|
}
|
|
@@ -2274,98 +2379,411 @@ const _Scheduler = class _Scheduler {
|
|
|
2274
2379
|
this.triggerError(error instanceof Error ? error : new Error(String(error)));
|
|
2275
2380
|
}
|
|
2276
2381
|
}
|
|
2277
|
-
}
|
|
2278
|
-
//* Debug & Inspection Methods ================================
|
|
2279
|
-
/**
|
|
2280
|
-
* Get the total number of registered jobs across all roots.
|
|
2281
|
-
* Includes both per-root jobs and global before/after jobs.
|
|
2282
|
-
* @returns {number} Total job count
|
|
2283
|
-
*/
|
|
2284
|
-
getJobCount() {
|
|
2285
|
-
let count = 0;
|
|
2286
|
-
for (const root of this.roots.values()) {
|
|
2287
|
-
count += root.jobs.size;
|
|
2382
|
+
}
|
|
2383
|
+
//* Debug & Inspection Methods ================================
|
|
2384
|
+
/**
|
|
2385
|
+
* Get the total number of registered jobs across all roots.
|
|
2386
|
+
* Includes both per-root jobs and global before/after jobs.
|
|
2387
|
+
* @returns {number} Total job count
|
|
2388
|
+
*/
|
|
2389
|
+
getJobCount() {
|
|
2390
|
+
let count = 0;
|
|
2391
|
+
for (const root of this.roots.values()) {
|
|
2392
|
+
count += root.jobs.size;
|
|
2393
|
+
}
|
|
2394
|
+
return count + this.globalBeforeJobs.size + this.globalAfterJobs.size;
|
|
2395
|
+
}
|
|
2396
|
+
/**
|
|
2397
|
+
* Get all registered job IDs across all roots.
|
|
2398
|
+
* Includes both per-root jobs and global before/after jobs.
|
|
2399
|
+
* @returns {string[]} Array of all job IDs
|
|
2400
|
+
*/
|
|
2401
|
+
getJobIds() {
|
|
2402
|
+
const ids = [];
|
|
2403
|
+
for (const root of this.roots.values()) {
|
|
2404
|
+
ids.push(...root.jobs.keys());
|
|
2405
|
+
}
|
|
2406
|
+
ids.push(...this.globalBeforeJobs.keys());
|
|
2407
|
+
ids.push(...this.globalAfterJobs.keys());
|
|
2408
|
+
return ids;
|
|
2409
|
+
}
|
|
2410
|
+
/**
|
|
2411
|
+
* Get the number of registered roots (Canvas instances).
|
|
2412
|
+
* @returns {number} Number of registered roots
|
|
2413
|
+
*/
|
|
2414
|
+
getRootCount() {
|
|
2415
|
+
return this.roots.size;
|
|
2416
|
+
}
|
|
2417
|
+
/**
|
|
2418
|
+
* Check if any user (non-system) jobs are registered in a specific phase.
|
|
2419
|
+
* Used by the default render job to know if a user has taken over rendering.
|
|
2420
|
+
*
|
|
2421
|
+
* @param phase The phase to check
|
|
2422
|
+
* @param rootId Optional root ID to check (checks all roots if not provided)
|
|
2423
|
+
* @returns true if any user jobs exist in the phase
|
|
2424
|
+
*/
|
|
2425
|
+
hasUserJobsInPhase(phase, rootId) {
|
|
2426
|
+
const rootsToCheck = rootId ? [this.roots.get(rootId)].filter(Boolean) : Array.from(this.roots.values());
|
|
2427
|
+
return rootsToCheck.some((root) => {
|
|
2428
|
+
if (!root) return false;
|
|
2429
|
+
for (const job of root.jobs.values()) {
|
|
2430
|
+
if (job.phase === phase && !job.system && job.enabled) return true;
|
|
2431
|
+
}
|
|
2432
|
+
return false;
|
|
2433
|
+
});
|
|
2434
|
+
}
|
|
2435
|
+
//* Utility Methods ================================
|
|
2436
|
+
/**
|
|
2437
|
+
* Generate a unique root ID for automatic root registration.
|
|
2438
|
+
* @returns {string} A unique root ID in the format 'root_N'
|
|
2439
|
+
*/
|
|
2440
|
+
generateRootId() {
|
|
2441
|
+
return `root_${this.nextRootIndex++}`;
|
|
2442
|
+
}
|
|
2443
|
+
/**
|
|
2444
|
+
* Generate a unique job ID.
|
|
2445
|
+
* @returns {string} A unique job ID in the format 'job_N'
|
|
2446
|
+
* @private
|
|
2447
|
+
*/
|
|
2448
|
+
generateJobId() {
|
|
2449
|
+
return `job_${this.nextJobIndex}`;
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* Normalize before/after constraints to a Set.
|
|
2453
|
+
* Handles undefined, single string, or array inputs.
|
|
2454
|
+
* @param {string | string[] | undefined} value - The constraint value(s)
|
|
2455
|
+
* @returns {Set<string>} Normalized Set of constraint strings
|
|
2456
|
+
* @private
|
|
2457
|
+
*/
|
|
2458
|
+
normalizeConstraints(value) {
|
|
2459
|
+
if (!value) return /* @__PURE__ */ new Set();
|
|
2460
|
+
if (Array.isArray(value)) return new Set(value);
|
|
2461
|
+
return /* @__PURE__ */ new Set([value]);
|
|
2462
|
+
}
|
|
2463
|
+
};
|
|
2464
|
+
//* Static State & Methods (Singleton Usage) ================================
|
|
2465
|
+
//* Cross-Bundle Singleton Key ==============================
|
|
2466
|
+
// Use Symbol.for() to ensure scheduler is shared across bundle boundaries
|
|
2467
|
+
// This prevents issues when mixing imports from @react-three/fiber and @react-three/fiber/webgpu
|
|
2468
|
+
__publicField$1(_Scheduler, "INSTANCE_KEY", Symbol.for("@react-three/fiber.scheduler"));
|
|
2469
|
+
let Scheduler = _Scheduler;
|
|
2470
|
+
const getScheduler = () => Scheduler.get();
|
|
2471
|
+
if (hmrData) {
|
|
2472
|
+
hmrData.accept?.();
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
|
|
2476
|
+
const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React.createContext(null));
|
|
2477
|
+
const createStore = (invalidate, advance) => {
|
|
2478
|
+
const rootStore = createWithEqualityFn((set, get) => {
|
|
2479
|
+
const position = new Vector3();
|
|
2480
|
+
const defaultTarget = new Vector3();
|
|
2481
|
+
const tempTarget = new Vector3();
|
|
2482
|
+
function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
|
|
2483
|
+
const { width, height, top, left } = size;
|
|
2484
|
+
const aspect = width / height;
|
|
2485
|
+
if (target.isVector3) tempTarget.copy(target);
|
|
2486
|
+
else tempTarget.set(...target);
|
|
2487
|
+
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
2488
|
+
if (isOrthographicCamera(camera)) {
|
|
2489
|
+
return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
|
|
2490
|
+
} else {
|
|
2491
|
+
const fov = camera.fov * Math.PI / 180;
|
|
2492
|
+
const h = 2 * Math.tan(fov / 2) * distance;
|
|
2493
|
+
const w = h * (width / height);
|
|
2494
|
+
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
let performanceTimeout = void 0;
|
|
2498
|
+
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
2499
|
+
const pointer = new Vector2();
|
|
2500
|
+
const rootState = {
|
|
2501
|
+
set,
|
|
2502
|
+
get,
|
|
2503
|
+
// Mock objects that have to be configured
|
|
2504
|
+
// primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
|
|
2505
|
+
primaryStore: null,
|
|
2506
|
+
gl: null,
|
|
2507
|
+
renderer: null,
|
|
2508
|
+
camera: null,
|
|
2509
|
+
frustum: new Frustum(),
|
|
2510
|
+
autoUpdateFrustum: true,
|
|
2511
|
+
raycaster: null,
|
|
2512
|
+
events: { priority: 1, enabled: true, connected: false },
|
|
2513
|
+
scene: null,
|
|
2514
|
+
rootScene: null,
|
|
2515
|
+
xr: null,
|
|
2516
|
+
inspector: null,
|
|
2517
|
+
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
2518
|
+
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
2519
|
+
textureColorSpace: SRGBColorSpace,
|
|
2520
|
+
isLegacy: false,
|
|
2521
|
+
webGPUSupported: false,
|
|
2522
|
+
isNative: false,
|
|
2523
|
+
controls: null,
|
|
2524
|
+
pointer,
|
|
2525
|
+
mouse: pointer,
|
|
2526
|
+
frameloop: "always",
|
|
2527
|
+
onPointerMissed: void 0,
|
|
2528
|
+
onDragOverMissed: void 0,
|
|
2529
|
+
onDropMissed: void 0,
|
|
2530
|
+
performance: {
|
|
2531
|
+
current: 1,
|
|
2532
|
+
min: 0.5,
|
|
2533
|
+
max: 1,
|
|
2534
|
+
debounce: 200,
|
|
2535
|
+
regress: () => {
|
|
2536
|
+
const state2 = get();
|
|
2537
|
+
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
2538
|
+
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
2539
|
+
performanceTimeout = setTimeout(
|
|
2540
|
+
() => setPerformanceCurrent(get().performance.max),
|
|
2541
|
+
state2.performance.debounce
|
|
2542
|
+
);
|
|
2543
|
+
}
|
|
2544
|
+
},
|
|
2545
|
+
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
2546
|
+
viewport: {
|
|
2547
|
+
initialDpr: 0,
|
|
2548
|
+
dpr: 0,
|
|
2549
|
+
width: 0,
|
|
2550
|
+
height: 0,
|
|
2551
|
+
top: 0,
|
|
2552
|
+
left: 0,
|
|
2553
|
+
aspect: 0,
|
|
2554
|
+
distance: 0,
|
|
2555
|
+
factor: 0,
|
|
2556
|
+
getCurrentViewport
|
|
2557
|
+
},
|
|
2558
|
+
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
2559
|
+
setSize: (width, height, top, left) => {
|
|
2560
|
+
const state2 = get();
|
|
2561
|
+
if (width === void 0) {
|
|
2562
|
+
set({ _sizeImperative: false });
|
|
2563
|
+
if (state2._sizeProps) {
|
|
2564
|
+
const { width: propW, height: propH } = state2._sizeProps;
|
|
2565
|
+
if (propW !== void 0 || propH !== void 0) {
|
|
2566
|
+
const currentSize = state2.size;
|
|
2567
|
+
const newSize = {
|
|
2568
|
+
width: propW ?? currentSize.width,
|
|
2569
|
+
height: propH ?? currentSize.height,
|
|
2570
|
+
top: currentSize.top,
|
|
2571
|
+
left: currentSize.left
|
|
2572
|
+
};
|
|
2573
|
+
set((s) => ({
|
|
2574
|
+
size: newSize,
|
|
2575
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
2576
|
+
}));
|
|
2577
|
+
getScheduler().invalidate();
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
return;
|
|
2581
|
+
}
|
|
2582
|
+
const w = width;
|
|
2583
|
+
const h = height ?? width;
|
|
2584
|
+
const t = top ?? state2.size.top;
|
|
2585
|
+
const l = left ?? state2.size.left;
|
|
2586
|
+
const size = { width: w, height: h, top: t, left: l };
|
|
2587
|
+
set((s) => ({
|
|
2588
|
+
size,
|
|
2589
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
2590
|
+
_sizeImperative: true
|
|
2591
|
+
}));
|
|
2592
|
+
getScheduler().invalidate();
|
|
2593
|
+
},
|
|
2594
|
+
setDpr: (dpr) => set((state2) => {
|
|
2595
|
+
const resolved = calculateDpr(dpr);
|
|
2596
|
+
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
2597
|
+
}),
|
|
2598
|
+
setFrameloop: (frameloop = "always") => {
|
|
2599
|
+
set(() => ({ frameloop }));
|
|
2600
|
+
},
|
|
2601
|
+
setError: (error) => set(() => ({ error })),
|
|
2602
|
+
error: null,
|
|
2603
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
|
|
2604
|
+
uniforms: {},
|
|
2605
|
+
nodes: {},
|
|
2606
|
+
textures: /* @__PURE__ */ new Map(),
|
|
2607
|
+
postProcessing: null,
|
|
2608
|
+
passes: {},
|
|
2609
|
+
_hmrVersion: 0,
|
|
2610
|
+
_sizeImperative: false,
|
|
2611
|
+
_sizeProps: null,
|
|
2612
|
+
previousRoot: void 0,
|
|
2613
|
+
internal: {
|
|
2614
|
+
// Events
|
|
2615
|
+
interaction: [],
|
|
2616
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2617
|
+
subscribers: [],
|
|
2618
|
+
initialClick: [0, 0],
|
|
2619
|
+
initialHits: [],
|
|
2620
|
+
capturedMap: /* @__PURE__ */ new Map(),
|
|
2621
|
+
lastEvent: React.createRef(),
|
|
2622
|
+
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2623
|
+
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2624
|
+
// Occlusion system (WebGPU only)
|
|
2625
|
+
occlusionEnabled: false,
|
|
2626
|
+
occlusionObserver: null,
|
|
2627
|
+
occlusionCache: /* @__PURE__ */ new Map(),
|
|
2628
|
+
helperGroup: null,
|
|
2629
|
+
// Updates
|
|
2630
|
+
active: false,
|
|
2631
|
+
frames: 0,
|
|
2632
|
+
priority: 0,
|
|
2633
|
+
subscribe: (ref, priority, store) => {
|
|
2634
|
+
const internal = get().internal;
|
|
2635
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
2636
|
+
internal.subscribers.push({ ref, priority, store });
|
|
2637
|
+
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
2638
|
+
return () => {
|
|
2639
|
+
const internal2 = get().internal;
|
|
2640
|
+
if (internal2?.subscribers) {
|
|
2641
|
+
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
2642
|
+
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
2643
|
+
}
|
|
2644
|
+
};
|
|
2645
|
+
},
|
|
2646
|
+
// Renderer Storage (single source of truth)
|
|
2647
|
+
actualRenderer: null,
|
|
2648
|
+
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
2649
|
+
scheduler: null
|
|
2650
|
+
}
|
|
2651
|
+
};
|
|
2652
|
+
return rootState;
|
|
2653
|
+
});
|
|
2654
|
+
const state = rootStore.getState();
|
|
2655
|
+
Object.defineProperty(state, "gl", {
|
|
2656
|
+
get() {
|
|
2657
|
+
const currentState = rootStore.getState();
|
|
2658
|
+
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
2659
|
+
const stack = new Error().stack || "";
|
|
2660
|
+
const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
|
|
2661
|
+
if (!isInternalAccess) {
|
|
2662
|
+
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
2663
|
+
notifyDepreciated({
|
|
2664
|
+
heading: "Accessing state.gl in WebGPU mode",
|
|
2665
|
+
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
|
|
2666
|
+
});
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
return currentState.internal.actualRenderer;
|
|
2670
|
+
},
|
|
2671
|
+
set(value) {
|
|
2672
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
2673
|
+
},
|
|
2674
|
+
enumerable: true,
|
|
2675
|
+
configurable: true
|
|
2676
|
+
});
|
|
2677
|
+
Object.defineProperty(state, "renderer", {
|
|
2678
|
+
get() {
|
|
2679
|
+
return rootStore.getState().internal.actualRenderer;
|
|
2680
|
+
},
|
|
2681
|
+
set(value) {
|
|
2682
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
2683
|
+
},
|
|
2684
|
+
enumerable: true,
|
|
2685
|
+
configurable: true
|
|
2686
|
+
});
|
|
2687
|
+
let oldScene = state.scene;
|
|
2688
|
+
rootStore.subscribe(() => {
|
|
2689
|
+
const currentState = rootStore.getState();
|
|
2690
|
+
const { scene, rootScene, set } = currentState;
|
|
2691
|
+
if (scene !== oldScene) {
|
|
2692
|
+
oldScene = scene;
|
|
2693
|
+
if (scene?.isScene && scene !== rootScene) {
|
|
2694
|
+
set({ rootScene: scene });
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
});
|
|
2698
|
+
let oldSize = state.size;
|
|
2699
|
+
let oldDpr = state.viewport.dpr;
|
|
2700
|
+
let oldCamera = state.camera;
|
|
2701
|
+
rootStore.subscribe(() => {
|
|
2702
|
+
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
2703
|
+
const actualRenderer = internal.actualRenderer;
|
|
2704
|
+
const canvasTarget = internal.canvasTarget;
|
|
2705
|
+
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
2706
|
+
oldSize = size;
|
|
2707
|
+
oldDpr = viewport.dpr;
|
|
2708
|
+
updateCamera(camera, size);
|
|
2709
|
+
if (canvasTarget) {
|
|
2710
|
+
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2711
|
+
const updateStyle = typeof HTMLCanvasElement !== "undefined" && canvasTarget.domElement instanceof HTMLCanvasElement;
|
|
2712
|
+
canvasTarget.setSize(size.width, size.height, updateStyle);
|
|
2713
|
+
} else {
|
|
2714
|
+
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
2715
|
+
const updateStyle = typeof HTMLCanvasElement !== "undefined" && actualRenderer.domElement instanceof HTMLCanvasElement;
|
|
2716
|
+
actualRenderer.setSize(size.width, size.height, updateStyle);
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
if (camera !== oldCamera) {
|
|
2720
|
+
oldCamera = camera;
|
|
2721
|
+
const { rootScene } = rootStore.getState();
|
|
2722
|
+
if (camera && rootScene && !camera.parent) {
|
|
2723
|
+
rootScene.add(camera);
|
|
2724
|
+
}
|
|
2725
|
+
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
2726
|
+
const currentState = rootStore.getState();
|
|
2727
|
+
if (currentState.autoUpdateFrustum && camera) {
|
|
2728
|
+
updateFrustum(camera, currentState.frustum);
|
|
2729
|
+
}
|
|
2288
2730
|
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2731
|
+
});
|
|
2732
|
+
rootStore.subscribe((state2) => invalidate(state2));
|
|
2733
|
+
return rootStore;
|
|
2734
|
+
};
|
|
2735
|
+
|
|
2736
|
+
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
2737
|
+
const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
2738
|
+
function getLoader(Proto) {
|
|
2739
|
+
if (isConstructor$1(Proto)) {
|
|
2740
|
+
let loader = memoizedLoaders.get(Proto);
|
|
2741
|
+
if (!loader) {
|
|
2742
|
+
loader = new Proto();
|
|
2743
|
+
memoizedLoaders.set(Proto, loader);
|
|
2300
2744
|
}
|
|
2301
|
-
|
|
2302
|
-
ids.push(...this.globalAfterJobs.keys());
|
|
2303
|
-
return ids;
|
|
2304
|
-
}
|
|
2305
|
-
/**
|
|
2306
|
-
* Get the number of registered roots (Canvas instances).
|
|
2307
|
-
* @returns {number} Number of registered roots
|
|
2308
|
-
*/
|
|
2309
|
-
getRootCount() {
|
|
2310
|
-
return this.roots.size;
|
|
2311
|
-
}
|
|
2312
|
-
/**
|
|
2313
|
-
* Check if any user (non-system) jobs are registered in a specific phase.
|
|
2314
|
-
* Used by the default render job to know if a user has taken over rendering.
|
|
2315
|
-
*
|
|
2316
|
-
* @param phase The phase to check
|
|
2317
|
-
* @param rootId Optional root ID to check (checks all roots if not provided)
|
|
2318
|
-
* @returns true if any user jobs exist in the phase
|
|
2319
|
-
*/
|
|
2320
|
-
hasUserJobsInPhase(phase, rootId) {
|
|
2321
|
-
const rootsToCheck = rootId ? [this.roots.get(rootId)].filter(Boolean) : Array.from(this.roots.values());
|
|
2322
|
-
return rootsToCheck.some((root) => {
|
|
2323
|
-
if (!root) return false;
|
|
2324
|
-
for (const job of root.jobs.values()) {
|
|
2325
|
-
if (job.phase === phase && !job.system && job.enabled) return true;
|
|
2326
|
-
}
|
|
2327
|
-
return false;
|
|
2328
|
-
});
|
|
2329
|
-
}
|
|
2330
|
-
//* Utility Methods ================================
|
|
2331
|
-
/**
|
|
2332
|
-
* Generate a unique root ID for automatic root registration.
|
|
2333
|
-
* @returns {string} A unique root ID in the format 'root_N'
|
|
2334
|
-
*/
|
|
2335
|
-
generateRootId() {
|
|
2336
|
-
return `root_${this.nextRootIndex++}`;
|
|
2337
|
-
}
|
|
2338
|
-
/**
|
|
2339
|
-
* Generate a unique job ID.
|
|
2340
|
-
* @returns {string} A unique job ID in the format 'job_N'
|
|
2341
|
-
* @private
|
|
2342
|
-
*/
|
|
2343
|
-
generateJobId() {
|
|
2344
|
-
return `job_${this.nextJobIndex}`;
|
|
2345
|
-
}
|
|
2346
|
-
/**
|
|
2347
|
-
* Normalize before/after constraints to a Set.
|
|
2348
|
-
* Handles undefined, single string, or array inputs.
|
|
2349
|
-
* @param {string | string[] | undefined} value - The constraint value(s)
|
|
2350
|
-
* @returns {Set<string>} Normalized Set of constraint strings
|
|
2351
|
-
* @private
|
|
2352
|
-
*/
|
|
2353
|
-
normalizeConstraints(value) {
|
|
2354
|
-
if (!value) return /* @__PURE__ */ new Set();
|
|
2355
|
-
if (Array.isArray(value)) return new Set(value);
|
|
2356
|
-
return /* @__PURE__ */ new Set([value]);
|
|
2745
|
+
return loader;
|
|
2357
2746
|
}
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
if (
|
|
2367
|
-
|
|
2747
|
+
return Proto;
|
|
2748
|
+
}
|
|
2749
|
+
function loadingFn(extensions, onProgress) {
|
|
2750
|
+
return function(Proto, input) {
|
|
2751
|
+
const loader = getLoader(Proto);
|
|
2752
|
+
if (extensions) extensions(loader);
|
|
2753
|
+
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
2754
|
+
return loader.loadAsync(input, onProgress).then((data) => {
|
|
2755
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
2756
|
+
return data;
|
|
2757
|
+
});
|
|
2758
|
+
}
|
|
2759
|
+
return new Promise(
|
|
2760
|
+
(res, reject) => loader.load(
|
|
2761
|
+
input,
|
|
2762
|
+
(data) => {
|
|
2763
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
2764
|
+
res(data);
|
|
2765
|
+
},
|
|
2766
|
+
onProgress,
|
|
2767
|
+
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
2768
|
+
)
|
|
2769
|
+
);
|
|
2770
|
+
};
|
|
2771
|
+
}
|
|
2772
|
+
function useLoader(loader, input, extensions, onProgress) {
|
|
2773
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
2774
|
+
const fn = loadingFn(extensions, onProgress);
|
|
2775
|
+
const results = keys.map((key) => suspend(fn, [loader, key], { equal: is.equ }));
|
|
2776
|
+
return Array.isArray(input) ? results : results[0];
|
|
2368
2777
|
}
|
|
2778
|
+
useLoader.preload = function(loader, input, extensions, onProgress) {
|
|
2779
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
2780
|
+
keys.forEach((key) => preload(loadingFn(extensions, onProgress), [loader, key]));
|
|
2781
|
+
};
|
|
2782
|
+
useLoader.clear = function(loader, input) {
|
|
2783
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
2784
|
+
keys.forEach((key) => clear([loader, key]));
|
|
2785
|
+
};
|
|
2786
|
+
useLoader.loader = getLoader;
|
|
2369
2787
|
|
|
2370
2788
|
function useFrame(callback, priorityOrOptions) {
|
|
2371
2789
|
const store = React.useContext(context);
|
|
@@ -2546,6 +2964,9 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
2546
2964
|
const textureCache = useThree((state) => state.textures);
|
|
2547
2965
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
2548
2966
|
const { onLoad, cache = false } = options;
|
|
2967
|
+
const onLoadRef = useRef(onLoad);
|
|
2968
|
+
onLoadRef.current = onLoad;
|
|
2969
|
+
const onLoadCalledForRef = useRef(null);
|
|
2549
2970
|
const urls = useMemo(() => getUrls(input), [input]);
|
|
2550
2971
|
const cachedResult = useMemo(() => {
|
|
2551
2972
|
if (!cache) return null;
|
|
@@ -2556,9 +2977,13 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
2556
2977
|
TextureLoader,
|
|
2557
2978
|
IsObject(input) ? Object.values(input) : input
|
|
2558
2979
|
);
|
|
2980
|
+
const inputKey = urls.join("\0");
|
|
2559
2981
|
useLayoutEffect(() => {
|
|
2560
|
-
if (
|
|
2561
|
-
|
|
2982
|
+
if (cachedResult) return;
|
|
2983
|
+
if (onLoadCalledForRef.current === inputKey) return;
|
|
2984
|
+
onLoadCalledForRef.current = inputKey;
|
|
2985
|
+
onLoadRef.current?.(loadedTextures);
|
|
2986
|
+
}, [cachedResult, loadedTextures, inputKey]);
|
|
2562
2987
|
useEffect(() => {
|
|
2563
2988
|
if (cachedResult) return;
|
|
2564
2989
|
if ("initTexture" in renderer) {
|
|
@@ -2725,14 +3150,31 @@ function useTextures() {
|
|
|
2725
3150
|
}, [store]);
|
|
2726
3151
|
}
|
|
2727
3152
|
|
|
2728
|
-
function useRenderTarget(
|
|
3153
|
+
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
2729
3154
|
const isLegacy = useThree((s) => s.isLegacy);
|
|
2730
3155
|
const size = useThree((s) => s.size);
|
|
3156
|
+
let width;
|
|
3157
|
+
let height;
|
|
3158
|
+
let opts;
|
|
3159
|
+
if (typeof widthOrOptions === "object") {
|
|
3160
|
+
opts = widthOrOptions;
|
|
3161
|
+
} else if (typeof widthOrOptions === "number") {
|
|
3162
|
+
width = widthOrOptions;
|
|
3163
|
+
if (typeof heightOrOptions === "object") {
|
|
3164
|
+
height = widthOrOptions;
|
|
3165
|
+
opts = heightOrOptions;
|
|
3166
|
+
} else if (typeof heightOrOptions === "number") {
|
|
3167
|
+
height = heightOrOptions;
|
|
3168
|
+
opts = options;
|
|
3169
|
+
} else {
|
|
3170
|
+
height = widthOrOptions;
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
2731
3173
|
return useMemo(() => {
|
|
2732
3174
|
const w = width ?? size.width;
|
|
2733
3175
|
const h = height ?? size.height;
|
|
2734
|
-
return new RenderTarget(w, h,
|
|
2735
|
-
}, [width, height, size.width, size.height,
|
|
3176
|
+
return new RenderTarget(w, h, opts);
|
|
3177
|
+
}, [width, height, size.width, size.height, opts, isLegacy]);
|
|
2736
3178
|
}
|
|
2737
3179
|
|
|
2738
3180
|
function useStore() {
|
|
@@ -2782,7 +3224,7 @@ function addTail(callback) {
|
|
|
2782
3224
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
2783
3225
|
getScheduler().invalidate(frames, stackFrames);
|
|
2784
3226
|
}
|
|
2785
|
-
function advance(timestamp
|
|
3227
|
+
function advance(timestamp) {
|
|
2786
3228
|
getScheduler().step(timestamp);
|
|
2787
3229
|
}
|
|
2788
3230
|
|
|
@@ -14236,6 +14678,7 @@ function swapInstances() {
|
|
|
14236
14678
|
instance.object = instance.props.object ?? new target(...instance.props.args ?? []);
|
|
14237
14679
|
instance.object.__r3f = instance;
|
|
14238
14680
|
setFiberRef(fiber, instance.object);
|
|
14681
|
+
delete instance.appliedOnce;
|
|
14239
14682
|
applyProps(instance.object, instance.props);
|
|
14240
14683
|
if (instance.props.attach) {
|
|
14241
14684
|
attach(parent, instance);
|
|
@@ -14309,8 +14752,22 @@ const reconciler = /* @__PURE__ */ createReconciler({
|
|
|
14309
14752
|
const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
|
|
14310
14753
|
if (isTailSibling) swapInstances();
|
|
14311
14754
|
},
|
|
14312
|
-
finalizeInitialChildren: () =>
|
|
14313
|
-
|
|
14755
|
+
finalizeInitialChildren: (instance) => {
|
|
14756
|
+
for (const prop in instance.props) {
|
|
14757
|
+
if (isFromRef(instance.props[prop])) return true;
|
|
14758
|
+
}
|
|
14759
|
+
return false;
|
|
14760
|
+
},
|
|
14761
|
+
commitMount(instance) {
|
|
14762
|
+
const resolved = {};
|
|
14763
|
+
for (const prop in instance.props) {
|
|
14764
|
+
const value = instance.props[prop];
|
|
14765
|
+
if (isFromRef(value)) {
|
|
14766
|
+
const ref = value[FROM_REF];
|
|
14767
|
+
if (ref.current != null) resolved[prop] = ref.current;
|
|
14768
|
+
}
|
|
14769
|
+
}
|
|
14770
|
+
if (Object.keys(resolved).length) applyProps(instance.object, resolved);
|
|
14314
14771
|
},
|
|
14315
14772
|
getPublicInstance: (instance) => instance?.object,
|
|
14316
14773
|
prepareForCommit: () => null,
|
|
@@ -14531,6 +14988,9 @@ function createRoot(canvas) {
|
|
|
14531
14988
|
let resolve;
|
|
14532
14989
|
pending = new Promise((_resolve) => resolve = _resolve);
|
|
14533
14990
|
const {
|
|
14991
|
+
id: canvasId,
|
|
14992
|
+
primaryCanvas,
|
|
14993
|
+
scheduler: schedulerConfig,
|
|
14534
14994
|
gl: glConfig,
|
|
14535
14995
|
renderer: rendererConfig,
|
|
14536
14996
|
size: propsSize,
|
|
@@ -14538,10 +14998,7 @@ function createRoot(canvas) {
|
|
|
14538
14998
|
events,
|
|
14539
14999
|
onCreated: onCreatedCallback,
|
|
14540
15000
|
shadows = false,
|
|
14541
|
-
linear = false,
|
|
14542
|
-
flat = false,
|
|
14543
15001
|
textureColorSpace = SRGBColorSpace,
|
|
14544
|
-
legacy = false,
|
|
14545
15002
|
orthographic = false,
|
|
14546
15003
|
frameloop = "always",
|
|
14547
15004
|
dpr = [1, 2],
|
|
@@ -14553,11 +15010,13 @@ function createRoot(canvas) {
|
|
|
14553
15010
|
onDropMissed,
|
|
14554
15011
|
autoUpdateFrustum = true,
|
|
14555
15012
|
occlusion = false,
|
|
14556
|
-
_sizeProps
|
|
15013
|
+
_sizeProps,
|
|
15014
|
+
forceEven
|
|
14557
15015
|
} = props;
|
|
14558
15016
|
const state = store.getState();
|
|
14559
15017
|
const defaultGPUProps = {
|
|
14560
|
-
canvas
|
|
15018
|
+
canvas,
|
|
15019
|
+
antialias: true
|
|
14561
15020
|
};
|
|
14562
15021
|
if (glConfig && !R3F_BUILD_LEGACY) {
|
|
14563
15022
|
throw new Error(
|
|
@@ -14568,7 +15027,27 @@ function createRoot(canvas) {
|
|
|
14568
15027
|
throw new Error("Cannot use both gl and renderer props at the same time");
|
|
14569
15028
|
}
|
|
14570
15029
|
let renderer = state.internal.actualRenderer;
|
|
14571
|
-
if (!state.internal.actualRenderer) {
|
|
15030
|
+
if (primaryCanvas && !state.internal.actualRenderer) {
|
|
15031
|
+
const primary = await waitForPrimary(primaryCanvas);
|
|
15032
|
+
renderer = primary.renderer;
|
|
15033
|
+
state.internal.actualRenderer = renderer;
|
|
15034
|
+
const canvasTarget = new CanvasTarget(canvas);
|
|
15035
|
+
primary.store.setState((prev) => ({
|
|
15036
|
+
internal: { ...prev.internal, isMultiCanvas: true }
|
|
15037
|
+
}));
|
|
15038
|
+
state.set((prev) => ({
|
|
15039
|
+
webGPUSupported: primary.store.getState().webGPUSupported,
|
|
15040
|
+
renderer,
|
|
15041
|
+
primaryStore: primary.store,
|
|
15042
|
+
internal: {
|
|
15043
|
+
...prev.internal,
|
|
15044
|
+
canvasTarget,
|
|
15045
|
+
isMultiCanvas: true,
|
|
15046
|
+
isSecondary: true,
|
|
15047
|
+
targetId: primaryCanvas
|
|
15048
|
+
}
|
|
15049
|
+
}));
|
|
15050
|
+
} else if (!state.internal.actualRenderer) {
|
|
14572
15051
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, WebGPURenderer);
|
|
14573
15052
|
if (!renderer.hasInitialized?.()) {
|
|
14574
15053
|
await renderer.init();
|
|
@@ -14576,7 +15055,18 @@ function createRoot(canvas) {
|
|
|
14576
15055
|
const backend = renderer.backend;
|
|
14577
15056
|
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
14578
15057
|
state.internal.actualRenderer = renderer;
|
|
14579
|
-
state.set({ webGPUSupported: isWebGPUBackend, renderer });
|
|
15058
|
+
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
15059
|
+
if (canvasId && !state.internal.isSecondary) {
|
|
15060
|
+
const canvasTarget = new CanvasTarget(canvas);
|
|
15061
|
+
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
15062
|
+
state.set((prev) => ({
|
|
15063
|
+
internal: {
|
|
15064
|
+
...prev.internal,
|
|
15065
|
+
canvasTarget,
|
|
15066
|
+
unregisterPrimary
|
|
15067
|
+
}
|
|
15068
|
+
}));
|
|
15069
|
+
}
|
|
14580
15070
|
}
|
|
14581
15071
|
let raycaster = state.raycaster;
|
|
14582
15072
|
if (!raycaster) state.set({ raycaster: raycaster = new Raycaster() });
|
|
@@ -14585,6 +15075,7 @@ function createRoot(canvas) {
|
|
|
14585
15075
|
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
14586
15076
|
applyProps(raycaster, { params: { ...raycaster.params, ...params } });
|
|
14587
15077
|
}
|
|
15078
|
+
let tempCamera = state.camera;
|
|
14588
15079
|
if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
|
|
14589
15080
|
lastCamera = cameraOptions;
|
|
14590
15081
|
const isCamera = cameraOptions?.isCamera;
|
|
@@ -14604,6 +15095,7 @@ function createRoot(canvas) {
|
|
|
14604
15095
|
if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
|
|
14605
15096
|
}
|
|
14606
15097
|
state.set({ camera });
|
|
15098
|
+
tempCamera = camera;
|
|
14607
15099
|
raycaster.camera = camera;
|
|
14608
15100
|
}
|
|
14609
15101
|
if (!state.scene) {
|
|
@@ -14621,7 +15113,7 @@ function createRoot(canvas) {
|
|
|
14621
15113
|
rootScene: scene,
|
|
14622
15114
|
internal: { ...prev.internal, container: scene }
|
|
14623
15115
|
}));
|
|
14624
|
-
const camera =
|
|
15116
|
+
const camera = tempCamera;
|
|
14625
15117
|
if (camera && !camera.parent) scene.add(camera);
|
|
14626
15118
|
}
|
|
14627
15119
|
if (events && !state.events.handlers) {
|
|
@@ -14638,6 +15130,9 @@ function createRoot(canvas) {
|
|
|
14638
15130
|
if (_sizeProps !== void 0) {
|
|
14639
15131
|
state.set({ _sizeProps });
|
|
14640
15132
|
}
|
|
15133
|
+
if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
|
|
15134
|
+
state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
|
|
15135
|
+
}
|
|
14641
15136
|
const size = computeInitialSize(canvas, propsSize);
|
|
14642
15137
|
if (!state._sizeImperative && !is.equ(size, state.size, shallowLoose)) {
|
|
14643
15138
|
const wasImperative = state._sizeImperative;
|
|
@@ -14667,7 +15162,7 @@ function createRoot(canvas) {
|
|
|
14667
15162
|
const handleXRFrame = (timestamp, frame) => {
|
|
14668
15163
|
const state2 = store.getState();
|
|
14669
15164
|
if (state2.frameloop === "never") return;
|
|
14670
|
-
advance(timestamp
|
|
15165
|
+
advance(timestamp);
|
|
14671
15166
|
};
|
|
14672
15167
|
const actualRenderer = state.internal.actualRenderer;
|
|
14673
15168
|
const handleSessionChange = () => {
|
|
@@ -14679,16 +15174,16 @@ function createRoot(canvas) {
|
|
|
14679
15174
|
};
|
|
14680
15175
|
const xr = {
|
|
14681
15176
|
connect() {
|
|
14682
|
-
const { gl, renderer: renderer2
|
|
14683
|
-
const
|
|
14684
|
-
|
|
14685
|
-
|
|
15177
|
+
const { gl, renderer: renderer2 } = store.getState();
|
|
15178
|
+
const xrManager = (renderer2 || gl).xr;
|
|
15179
|
+
xrManager.addEventListener("sessionstart", handleSessionChange);
|
|
15180
|
+
xrManager.addEventListener("sessionend", handleSessionChange);
|
|
14686
15181
|
},
|
|
14687
15182
|
disconnect() {
|
|
14688
|
-
const { gl, renderer: renderer2
|
|
14689
|
-
const
|
|
14690
|
-
|
|
14691
|
-
|
|
15183
|
+
const { gl, renderer: renderer2 } = store.getState();
|
|
15184
|
+
const xrManager = (renderer2 || gl).xr;
|
|
15185
|
+
xrManager.removeEventListener("sessionstart", handleSessionChange);
|
|
15186
|
+
xrManager.removeEventListener("sessionend", handleSessionChange);
|
|
14692
15187
|
}
|
|
14693
15188
|
};
|
|
14694
15189
|
if (typeof renderer.xr?.addEventListener === "function") xr.connect();
|
|
@@ -14716,6 +15211,10 @@ function createRoot(canvas) {
|
|
|
14716
15211
|
renderer.shadowMap.needsUpdate = true;
|
|
14717
15212
|
}
|
|
14718
15213
|
}
|
|
15214
|
+
if (!configured) {
|
|
15215
|
+
renderer.outputColorSpace = SRGBColorSpace;
|
|
15216
|
+
renderer.toneMapping = ACESFilmicToneMapping;
|
|
15217
|
+
}
|
|
14719
15218
|
if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
|
|
14720
15219
|
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
14721
15220
|
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
@@ -14732,11 +15231,26 @@ function createRoot(canvas) {
|
|
|
14732
15231
|
const scheduler = getScheduler();
|
|
14733
15232
|
const rootId = state.internal.rootId;
|
|
14734
15233
|
if (!rootId) {
|
|
14735
|
-
const newRootId = scheduler.generateRootId();
|
|
15234
|
+
const newRootId = canvasId || scheduler.generateRootId();
|
|
14736
15235
|
const unregisterRoot = scheduler.registerRoot(newRootId, {
|
|
14737
15236
|
getState: () => store.getState(),
|
|
14738
15237
|
onError: (err) => store.getState().setError(err)
|
|
14739
15238
|
});
|
|
15239
|
+
const unregisterCanvasTarget = scheduler.register(
|
|
15240
|
+
() => {
|
|
15241
|
+
const state2 = store.getState();
|
|
15242
|
+
if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
|
|
15243
|
+
const renderer2 = state2.internal.actualRenderer;
|
|
15244
|
+
renderer2.setCanvasTarget(state2.internal.canvasTarget);
|
|
15245
|
+
}
|
|
15246
|
+
},
|
|
15247
|
+
{
|
|
15248
|
+
id: `${newRootId}_canvasTarget`,
|
|
15249
|
+
rootId: newRootId,
|
|
15250
|
+
phase: "start",
|
|
15251
|
+
system: true
|
|
15252
|
+
}
|
|
15253
|
+
);
|
|
14740
15254
|
const unregisterFrustum = scheduler.register(
|
|
14741
15255
|
() => {
|
|
14742
15256
|
const state2 = store.getState();
|
|
@@ -14778,11 +15292,15 @@ function createRoot(canvas) {
|
|
|
14778
15292
|
}
|
|
14779
15293
|
},
|
|
14780
15294
|
{
|
|
14781
|
-
|
|
15295
|
+
// Use canvas ID directly as job ID if available, otherwise use generated rootId
|
|
15296
|
+
id: canvasId || `${newRootId}_render`,
|
|
14782
15297
|
rootId: newRootId,
|
|
14783
15298
|
phase: "render",
|
|
14784
|
-
system: true
|
|
15299
|
+
system: true,
|
|
14785
15300
|
// Internal flag: this is a system job, not user-controlled
|
|
15301
|
+
// Apply scheduler config for render ordering and rate limiting
|
|
15302
|
+
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
15303
|
+
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14786
15304
|
}
|
|
14787
15305
|
);
|
|
14788
15306
|
state.set((state2) => ({
|
|
@@ -14791,6 +15309,7 @@ function createRoot(canvas) {
|
|
|
14791
15309
|
rootId: newRootId,
|
|
14792
15310
|
unregisterRoot: () => {
|
|
14793
15311
|
unregisterRoot();
|
|
15312
|
+
unregisterCanvasTarget();
|
|
14794
15313
|
unregisterFrustum();
|
|
14795
15314
|
unregisterVisibility();
|
|
14796
15315
|
unregisterRender();
|
|
@@ -14849,15 +15368,24 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14849
15368
|
const renderer = state.internal.actualRenderer;
|
|
14850
15369
|
const unregisterRoot = state.internal.unregisterRoot;
|
|
14851
15370
|
if (unregisterRoot) unregisterRoot();
|
|
15371
|
+
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
15372
|
+
if (unregisterPrimary) unregisterPrimary();
|
|
15373
|
+
const canvasTarget = state.internal.canvasTarget;
|
|
15374
|
+
if (canvasTarget?.dispose) canvasTarget.dispose();
|
|
14852
15375
|
state.events.disconnect?.();
|
|
14853
15376
|
cleanupHelperGroup(root.store);
|
|
14854
|
-
renderer
|
|
14855
|
-
|
|
14856
|
-
|
|
15377
|
+
if (state.isLegacy && renderer) {
|
|
15378
|
+
;
|
|
15379
|
+
renderer.renderLists?.dispose?.();
|
|
15380
|
+
renderer.forceContextLoss?.();
|
|
15381
|
+
}
|
|
15382
|
+
if (!state.internal.isSecondary) {
|
|
15383
|
+
if (renderer?.xr) state.xr.disconnect();
|
|
15384
|
+
}
|
|
14857
15385
|
dispose(state.scene);
|
|
14858
15386
|
_roots.delete(canvas);
|
|
14859
15387
|
if (callback) callback(canvas);
|
|
14860
|
-
} catch
|
|
15388
|
+
} catch {
|
|
14861
15389
|
}
|
|
14862
15390
|
}, 500);
|
|
14863
15391
|
}
|
|
@@ -14865,36 +15393,34 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14865
15393
|
}
|
|
14866
15394
|
}
|
|
14867
15395
|
function createPortal(children, container, state) {
|
|
14868
|
-
return /* @__PURE__ */ jsx(
|
|
15396
|
+
return /* @__PURE__ */ jsx(Portal, { children, container, state });
|
|
14869
15397
|
}
|
|
14870
|
-
function
|
|
15398
|
+
function Portal({ children, container, state }) {
|
|
14871
15399
|
const isRef = useCallback((obj) => obj && "current" in obj, []);
|
|
14872
|
-
const [resolvedContainer,
|
|
15400
|
+
const [resolvedContainer, _setResolvedContainer] = useState(() => {
|
|
14873
15401
|
if (isRef(container)) return container.current ?? null;
|
|
14874
15402
|
return container;
|
|
14875
15403
|
});
|
|
15404
|
+
const setResolvedContainer = useCallback(
|
|
15405
|
+
(newContainer) => {
|
|
15406
|
+
if (!newContainer || newContainer === resolvedContainer) return;
|
|
15407
|
+
_setResolvedContainer(isRef(newContainer) ? newContainer.current : newContainer);
|
|
15408
|
+
},
|
|
15409
|
+
[resolvedContainer, _setResolvedContainer, isRef]
|
|
15410
|
+
);
|
|
14876
15411
|
useMemo(() => {
|
|
14877
|
-
if (isRef(container)) {
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
const updated = container.current;
|
|
14882
|
-
if (updated && updated !== resolvedContainer) {
|
|
14883
|
-
setResolvedContainer(updated);
|
|
14884
|
-
}
|
|
14885
|
-
});
|
|
14886
|
-
} else if (current !== resolvedContainer) {
|
|
14887
|
-
setResolvedContainer(current);
|
|
14888
|
-
}
|
|
14889
|
-
} else if (container !== resolvedContainer) {
|
|
14890
|
-
setResolvedContainer(container);
|
|
15412
|
+
if (isRef(container) && !container.current) {
|
|
15413
|
+
return queueMicrotask(() => {
|
|
15414
|
+
setResolvedContainer(container.current);
|
|
15415
|
+
});
|
|
14891
15416
|
}
|
|
14892
|
-
|
|
15417
|
+
setResolvedContainer(container);
|
|
15418
|
+
}, [container, isRef, setResolvedContainer]);
|
|
14893
15419
|
if (!resolvedContainer) return /* @__PURE__ */ jsx(Fragment, {});
|
|
14894
15420
|
const portalKey = resolvedContainer.uuid ?? `portal-${resolvedContainer.id ?? "unknown"}`;
|
|
14895
|
-
return /* @__PURE__ */ jsx(
|
|
15421
|
+
return /* @__PURE__ */ jsx(PortalInner, { children, container: resolvedContainer, state }, portalKey);
|
|
14896
15422
|
}
|
|
14897
|
-
function
|
|
15423
|
+
function PortalInner({ state = {}, children, container }) {
|
|
14898
15424
|
const { events, size, injectScene = true, ...rest } = state;
|
|
14899
15425
|
const previousRoot = useStore();
|
|
14900
15426
|
const [raycaster] = useState(() => new Raycaster());
|
|
@@ -14915,11 +15441,12 @@ function Portal({ state = {}, children, container }) {
|
|
|
14915
15441
|
};
|
|
14916
15442
|
}, [portalScene, container, injectScene]);
|
|
14917
15443
|
const inject = useMutableCallback((rootState, injectState) => {
|
|
15444
|
+
const resolvedSize = { ...rootState.size, ...injectState.size, ...size };
|
|
14918
15445
|
let viewport = void 0;
|
|
14919
|
-
if (injectState.camera && size) {
|
|
15446
|
+
if (injectState.camera && (size || injectState.size)) {
|
|
14920
15447
|
const camera = injectState.camera;
|
|
14921
|
-
viewport = rootState.viewport.getCurrentViewport(camera, new Vector3(),
|
|
14922
|
-
if (camera !== rootState.camera) updateCamera(camera,
|
|
15448
|
+
viewport = rootState.viewport.getCurrentViewport(camera, new Vector3(), resolvedSize);
|
|
15449
|
+
if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
|
|
14923
15450
|
}
|
|
14924
15451
|
return {
|
|
14925
15452
|
// The intersect consists of the previous root state
|
|
@@ -14936,7 +15463,7 @@ function Portal({ state = {}, children, container }) {
|
|
|
14936
15463
|
previousRoot,
|
|
14937
15464
|
// Events, size and viewport can be overridden by the inject layer
|
|
14938
15465
|
events: { ...rootState.events, ...injectState.events, ...events },
|
|
14939
|
-
size:
|
|
15466
|
+
size: resolvedSize,
|
|
14940
15467
|
viewport: { ...rootState.viewport, ...viewport },
|
|
14941
15468
|
// Layers are allowed to override events
|
|
14942
15469
|
setEvents: (events2) => injectState.set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
|
|
@@ -14970,15 +15497,13 @@ function CanvasImpl({
|
|
|
14970
15497
|
fallback,
|
|
14971
15498
|
resize,
|
|
14972
15499
|
style,
|
|
15500
|
+
id,
|
|
14973
15501
|
gl,
|
|
14974
|
-
renderer,
|
|
15502
|
+
renderer: rendererProp,
|
|
14975
15503
|
events = createPointerEvents,
|
|
14976
15504
|
eventSource,
|
|
14977
15505
|
eventPrefix,
|
|
14978
15506
|
shadows,
|
|
14979
|
-
linear,
|
|
14980
|
-
flat,
|
|
14981
|
-
legacy,
|
|
14982
15507
|
orthographic,
|
|
14983
15508
|
frameloop,
|
|
14984
15509
|
dpr,
|
|
@@ -14993,10 +15518,43 @@ function CanvasImpl({
|
|
|
14993
15518
|
hmr,
|
|
14994
15519
|
width,
|
|
14995
15520
|
height,
|
|
15521
|
+
background,
|
|
15522
|
+
forceEven,
|
|
14996
15523
|
...props
|
|
14997
15524
|
}) {
|
|
15525
|
+
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 };
|
|
15526
|
+
const renderer = Object.keys(rendererConfig).length > 0 ? rendererConfig : rendererProp;
|
|
14998
15527
|
React.useMemo(() => extend(THREE), []);
|
|
14999
15528
|
const Bridge = useBridge();
|
|
15529
|
+
const backgroundProps = React.useMemo(() => {
|
|
15530
|
+
if (!background) return null;
|
|
15531
|
+
if (typeof background === "object" && !background.isColor) {
|
|
15532
|
+
const { backgroundMap, envMap, files, preset, ...rest } = background;
|
|
15533
|
+
return {
|
|
15534
|
+
...rest,
|
|
15535
|
+
preset,
|
|
15536
|
+
files: envMap || files,
|
|
15537
|
+
backgroundFiles: backgroundMap,
|
|
15538
|
+
background: true
|
|
15539
|
+
};
|
|
15540
|
+
}
|
|
15541
|
+
if (typeof background === "number") {
|
|
15542
|
+
return { color: background, background: true };
|
|
15543
|
+
}
|
|
15544
|
+
if (typeof background === "string") {
|
|
15545
|
+
if (background in presetsObj) {
|
|
15546
|
+
return { preset: background, background: true };
|
|
15547
|
+
}
|
|
15548
|
+
if (/^(https?:\/\/|\/|\.\/|\.\.\/)|\\.(hdr|exr|jpg|jpeg|png|webp|gif)$/i.test(background)) {
|
|
15549
|
+
return { files: background, background: true };
|
|
15550
|
+
}
|
|
15551
|
+
return { color: background, background: true };
|
|
15552
|
+
}
|
|
15553
|
+
if (background.isColor) {
|
|
15554
|
+
return { color: background, background: true };
|
|
15555
|
+
}
|
|
15556
|
+
return null;
|
|
15557
|
+
}, [background]);
|
|
15000
15558
|
const hasInitialSizeRef = React.useRef(false);
|
|
15001
15559
|
const measureConfig = React.useMemo(() => {
|
|
15002
15560
|
if (!hasInitialSizeRef.current) {
|
|
@@ -15013,15 +15571,20 @@ function CanvasImpl({
|
|
|
15013
15571
|
};
|
|
15014
15572
|
}, [resize, hasInitialSizeRef.current]);
|
|
15015
15573
|
const [containerRef, containerRect] = useMeasure(measureConfig);
|
|
15016
|
-
const effectiveSize = React.useMemo(
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
|
|
15574
|
+
const effectiveSize = React.useMemo(() => {
|
|
15575
|
+
let w = width ?? containerRect.width;
|
|
15576
|
+
let h = height ?? containerRect.height;
|
|
15577
|
+
if (forceEven) {
|
|
15578
|
+
w = Math.ceil(w / 2) * 2;
|
|
15579
|
+
h = Math.ceil(h / 2) * 2;
|
|
15580
|
+
}
|
|
15581
|
+
return {
|
|
15582
|
+
width: w,
|
|
15583
|
+
height: h,
|
|
15020
15584
|
top: containerRect.top,
|
|
15021
15585
|
left: containerRect.left
|
|
15022
|
-
}
|
|
15023
|
-
|
|
15024
|
-
);
|
|
15586
|
+
};
|
|
15587
|
+
}, [width, height, containerRect, forceEven]);
|
|
15025
15588
|
if (!hasInitialSizeRef.current && effectiveSize.width > 0 && effectiveSize.height > 0) {
|
|
15026
15589
|
hasInitialSizeRef.current = true;
|
|
15027
15590
|
}
|
|
@@ -15061,14 +15624,14 @@ function CanvasImpl({
|
|
|
15061
15624
|
async function run() {
|
|
15062
15625
|
if (!effectActiveRef.current || !root.current) return;
|
|
15063
15626
|
await root.current.configure({
|
|
15627
|
+
id,
|
|
15628
|
+
primaryCanvas,
|
|
15629
|
+
scheduler,
|
|
15064
15630
|
gl,
|
|
15065
15631
|
renderer,
|
|
15066
15632
|
scene,
|
|
15067
15633
|
events,
|
|
15068
15634
|
shadows,
|
|
15069
|
-
linear,
|
|
15070
|
-
flat,
|
|
15071
|
-
legacy,
|
|
15072
15635
|
orthographic,
|
|
15073
15636
|
frameloop,
|
|
15074
15637
|
dpr,
|
|
@@ -15078,6 +15641,7 @@ function CanvasImpl({
|
|
|
15078
15641
|
size: effectiveSize,
|
|
15079
15642
|
// Store size props for reset functionality
|
|
15080
15643
|
_sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
|
|
15644
|
+
forceEven,
|
|
15081
15645
|
// Pass mutable reference to onPointerMissed so it's free to update
|
|
15082
15646
|
onPointerMissed: (...args) => handlePointerMissed.current?.(...args),
|
|
15083
15647
|
onDragOverMissed: (...args) => handleDragOverMissed.current?.(...args),
|
|
@@ -15101,7 +15665,10 @@ function CanvasImpl({
|
|
|
15101
15665
|
});
|
|
15102
15666
|
if (!effectActiveRef.current || !root.current) return;
|
|
15103
15667
|
root.current.render(
|
|
15104
|
-
/* @__PURE__ */ jsx(Bridge, { children: /* @__PURE__ */ jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */
|
|
15668
|
+
/* @__PURE__ */ jsx(Bridge, { children: /* @__PURE__ */ jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxs(React.Suspense, { fallback: /* @__PURE__ */ jsx(Block, { set: setBlock }), children: [
|
|
15669
|
+
backgroundProps && /* @__PURE__ */ jsx(Environment, { ...backgroundProps }),
|
|
15670
|
+
children ?? null
|
|
15671
|
+
] }) }) })
|
|
15105
15672
|
);
|
|
15106
15673
|
}
|
|
15107
15674
|
run();
|
|
@@ -15128,14 +15695,16 @@ function CanvasImpl({
|
|
|
15128
15695
|
const canvas = canvasRef.current;
|
|
15129
15696
|
if (!canvas) return;
|
|
15130
15697
|
const handleHMR = () => {
|
|
15131
|
-
|
|
15132
|
-
|
|
15133
|
-
rootEntry
|
|
15134
|
-
|
|
15135
|
-
|
|
15136
|
-
|
|
15137
|
-
|
|
15138
|
-
|
|
15698
|
+
queueMicrotask(() => {
|
|
15699
|
+
const rootEntry = _roots.get(canvas);
|
|
15700
|
+
if (rootEntry?.store) {
|
|
15701
|
+
rootEntry.store.setState((state) => ({
|
|
15702
|
+
nodes: {},
|
|
15703
|
+
uniforms: {},
|
|
15704
|
+
_hmrVersion: state._hmrVersion + 1
|
|
15705
|
+
}));
|
|
15706
|
+
}
|
|
15707
|
+
});
|
|
15139
15708
|
};
|
|
15140
15709
|
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
15141
15710
|
const hot = import.meta.hot;
|
|
@@ -15164,7 +15733,7 @@ function CanvasImpl({
|
|
|
15164
15733
|
...style
|
|
15165
15734
|
},
|
|
15166
15735
|
...props,
|
|
15167
|
-
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "r3f-canvas", style: { display: "block" }, children: fallback }) })
|
|
15736
|
+
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx("canvas", { ref: canvasRef, id, className: "r3f-canvas", style: { display: "block" }, children: fallback }) })
|
|
15168
15737
|
}
|
|
15169
15738
|
);
|
|
15170
15739
|
}
|
|
@@ -15237,6 +15806,22 @@ let ScopedStore = _ScopedStore;
|
|
|
15237
15806
|
function createScopedStore(data) {
|
|
15238
15807
|
return new ScopedStore(data);
|
|
15239
15808
|
}
|
|
15809
|
+
function createLazyCreatorState(state) {
|
|
15810
|
+
let _uniforms = null;
|
|
15811
|
+
let _nodes = null;
|
|
15812
|
+
return Object.create(state, {
|
|
15813
|
+
uniforms: {
|
|
15814
|
+
get() {
|
|
15815
|
+
return _uniforms ?? (_uniforms = createScopedStore(state.uniforms));
|
|
15816
|
+
}
|
|
15817
|
+
},
|
|
15818
|
+
nodes: {
|
|
15819
|
+
get() {
|
|
15820
|
+
return _nodes ?? (_nodes = createScopedStore(state.nodes));
|
|
15821
|
+
}
|
|
15822
|
+
}
|
|
15823
|
+
});
|
|
15824
|
+
}
|
|
15240
15825
|
|
|
15241
15826
|
function addTexture(set, key, value) {
|
|
15242
15827
|
set((state) => {
|
|
@@ -15277,6 +15862,27 @@ function createTextureOperations(set) {
|
|
|
15277
15862
|
removeMultiple: (keys) => removeTextures(set, keys)
|
|
15278
15863
|
};
|
|
15279
15864
|
}
|
|
15865
|
+
function extractTSLValue(value) {
|
|
15866
|
+
if (value === null || value === void 0) return value;
|
|
15867
|
+
if (typeof value !== "object") return value;
|
|
15868
|
+
const node = value;
|
|
15869
|
+
if (!node.isNode) return value;
|
|
15870
|
+
if (node.isConstNode) {
|
|
15871
|
+
return node.value;
|
|
15872
|
+
}
|
|
15873
|
+
if ("value" in node) {
|
|
15874
|
+
let extractedValue = node.value;
|
|
15875
|
+
if (typeof node.traverse === "function") {
|
|
15876
|
+
node.traverse((n) => {
|
|
15877
|
+
if (n.isConstNode) {
|
|
15878
|
+
extractedValue = n.value;
|
|
15879
|
+
}
|
|
15880
|
+
});
|
|
15881
|
+
}
|
|
15882
|
+
return extractedValue;
|
|
15883
|
+
}
|
|
15884
|
+
return value;
|
|
15885
|
+
}
|
|
15280
15886
|
function vectorize(inObject) {
|
|
15281
15887
|
if (inObject === null || inObject === void 0) return inObject;
|
|
15282
15888
|
if (typeof inObject === "string") {
|
|
@@ -15289,6 +15895,9 @@ function vectorize(inObject) {
|
|
|
15289
15895
|
}
|
|
15290
15896
|
if (typeof inObject !== "object") return inObject;
|
|
15291
15897
|
const obj = inObject;
|
|
15898
|
+
if (obj.isNode) {
|
|
15899
|
+
return extractTSLValue(inObject);
|
|
15900
|
+
}
|
|
15292
15901
|
if (obj.isVector2 || obj.isVector3 || obj.isVector4) return inObject;
|
|
15293
15902
|
if (obj.isMatrix3 || obj.isMatrix4) return inObject;
|
|
15294
15903
|
if (obj.isColor || obj.isEuler || obj.isQuaternion || obj.isSpherical) return inObject;
|
|
@@ -15354,17 +15963,14 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15354
15963
|
const rebuildUniforms = useCallback(
|
|
15355
15964
|
(targetScope) => {
|
|
15356
15965
|
store.setState((state) => {
|
|
15357
|
-
let newUniforms =
|
|
15966
|
+
let newUniforms = {};
|
|
15358
15967
|
if (targetScope && targetScope !== "root") {
|
|
15359
15968
|
const { [targetScope]: _, ...rest } = state.uniforms;
|
|
15360
15969
|
newUniforms = rest;
|
|
15361
15970
|
} else if (targetScope === "root") {
|
|
15362
|
-
newUniforms = {};
|
|
15363
15971
|
for (const [key, value] of Object.entries(state.uniforms)) {
|
|
15364
15972
|
if (!isUniformNode$1(value)) newUniforms[key] = value;
|
|
15365
15973
|
}
|
|
15366
|
-
} else {
|
|
15367
|
-
newUniforms = {};
|
|
15368
15974
|
}
|
|
15369
15975
|
return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
|
|
15370
15976
|
});
|
|
@@ -15372,20 +15978,26 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15372
15978
|
[store]
|
|
15373
15979
|
);
|
|
15374
15980
|
const inputForMemoization = useMemo(() => {
|
|
15981
|
+
let raw = creatorOrScope;
|
|
15375
15982
|
if (is.fun(creatorOrScope)) {
|
|
15376
|
-
const
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
15382
|
-
|
|
15983
|
+
const wrappedState = createLazyCreatorState(store.getState());
|
|
15984
|
+
raw = creatorOrScope(wrappedState);
|
|
15985
|
+
}
|
|
15986
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
15987
|
+
const normalized = {};
|
|
15988
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
15989
|
+
normalized[key] = vectorize(value);
|
|
15990
|
+
}
|
|
15991
|
+
return normalized;
|
|
15383
15992
|
}
|
|
15384
|
-
return
|
|
15993
|
+
return raw;
|
|
15385
15994
|
}, [creatorOrScope, store]);
|
|
15386
15995
|
const memoizedInput = useCompareMemoize(inputForMemoization);
|
|
15387
15996
|
const isReader = memoizedInput === void 0 || typeof memoizedInput === "string";
|
|
15388
15997
|
const storeUniforms = useThree((s) => s.uniforms);
|
|
15998
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
15999
|
+
const readerDep = isReader ? storeUniforms : null;
|
|
16000
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
15389
16001
|
const uniforms = useMemo(() => {
|
|
15390
16002
|
if (memoizedInput === void 0) {
|
|
15391
16003
|
return storeUniforms;
|
|
@@ -15440,28 +16052,19 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
15440
16052
|
}
|
|
15441
16053
|
}
|
|
15442
16054
|
return result;
|
|
15443
|
-
}, [
|
|
15444
|
-
store,
|
|
15445
|
-
memoizedInput,
|
|
15446
|
-
scope,
|
|
15447
|
-
// Only include storeUniforms in deps for reader modes to enable reactivity
|
|
15448
|
-
isReader ? storeUniforms : null
|
|
15449
|
-
]);
|
|
16055
|
+
}, [store, memoizedInput, scope, readerDep, creatorDep]);
|
|
15450
16056
|
return { ...uniforms, removeUniforms: removeUniforms2, clearUniforms, rebuildUniforms };
|
|
15451
16057
|
}
|
|
15452
16058
|
function rebuildAllUniforms(store, scope) {
|
|
15453
16059
|
store.setState((state) => {
|
|
15454
|
-
let newUniforms =
|
|
16060
|
+
let newUniforms = {};
|
|
15455
16061
|
if (scope && scope !== "root") {
|
|
15456
16062
|
const { [scope]: _, ...rest } = state.uniforms;
|
|
15457
16063
|
newUniforms = rest;
|
|
15458
16064
|
} else if (scope === "root") {
|
|
15459
|
-
newUniforms = {};
|
|
15460
16065
|
for (const [key, value] of Object.entries(state.uniforms)) {
|
|
15461
16066
|
if (!isUniformNode$1(value)) newUniforms[key] = value;
|
|
15462
16067
|
}
|
|
15463
|
-
} else {
|
|
15464
|
-
newUniforms = {};
|
|
15465
16068
|
}
|
|
15466
16069
|
return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
|
|
15467
16070
|
});
|
|
@@ -15529,15 +16132,17 @@ function isSameThreeType(a, b) {
|
|
|
15529
16132
|
}
|
|
15530
16133
|
|
|
15531
16134
|
const isUniformNode = (value) => value !== null && typeof value === "object" && "value" in value && "uuid" in value;
|
|
16135
|
+
const isTSLNode$1 = (value) => value !== null && typeof value === "object" && "uuid" in value && "nodeType" in value;
|
|
15532
16136
|
function useUniform(name, value) {
|
|
15533
16137
|
const store = useStore();
|
|
16138
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
15534
16139
|
return useMemo(() => {
|
|
15535
16140
|
const state = store.getState();
|
|
15536
16141
|
const set = store.setState;
|
|
15537
16142
|
const existing = state.uniforms[name];
|
|
15538
16143
|
if (existing && isUniformNode(existing)) {
|
|
15539
|
-
if (value !== void 0) {
|
|
15540
|
-
existing.value = value;
|
|
16144
|
+
if (value !== void 0 && !isTSLNode$1(value) && !isUniformNode(value)) {
|
|
16145
|
+
existing.value = typeof value === "string" ? new Color(value) : value;
|
|
15541
16146
|
}
|
|
15542
16147
|
return existing;
|
|
15543
16148
|
}
|
|
@@ -15546,7 +16151,24 @@ function useUniform(name, value) {
|
|
|
15546
16151
|
`[useUniform] Uniform "${name}" not found. Create it first with: useUniform('${name}', initialValue)`
|
|
15547
16152
|
);
|
|
15548
16153
|
}
|
|
15549
|
-
|
|
16154
|
+
if (isUniformNode(value)) {
|
|
16155
|
+
const node2 = value;
|
|
16156
|
+
if (typeof node2.setName === "function") {
|
|
16157
|
+
node2.setName(name);
|
|
16158
|
+
}
|
|
16159
|
+
set((s) => ({
|
|
16160
|
+
uniforms: { ...s.uniforms, [name]: node2 }
|
|
16161
|
+
}));
|
|
16162
|
+
return node2;
|
|
16163
|
+
}
|
|
16164
|
+
let node;
|
|
16165
|
+
if (isTSLNode$1(value)) {
|
|
16166
|
+
node = uniform(value);
|
|
16167
|
+
} else if (typeof value === "string") {
|
|
16168
|
+
node = uniform(new Color(value));
|
|
16169
|
+
} else {
|
|
16170
|
+
node = uniform(value);
|
|
16171
|
+
}
|
|
15550
16172
|
if (typeof node.setName === "function") {
|
|
15551
16173
|
node.setName(name);
|
|
15552
16174
|
}
|
|
@@ -15557,7 +16179,7 @@ function useUniform(name, value) {
|
|
|
15557
16179
|
}
|
|
15558
16180
|
}));
|
|
15559
16181
|
return node;
|
|
15560
|
-
}, [store, name]);
|
|
16182
|
+
}, [store, name, hmrVersion]);
|
|
15561
16183
|
}
|
|
15562
16184
|
|
|
15563
16185
|
const isTSLNode = (value) => value !== null && typeof value === "object" && ("uuid" in value || "nodeType" in value);
|
|
@@ -15621,6 +16243,9 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15621
16243
|
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
15622
16244
|
const storeNodes = useThree((s) => s.nodes);
|
|
15623
16245
|
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16246
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16247
|
+
const readerDep = isReader ? storeNodes : null;
|
|
16248
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
15624
16249
|
const nodes = useMemo(() => {
|
|
15625
16250
|
if (creatorOrScope === void 0) {
|
|
15626
16251
|
return storeNodes;
|
|
@@ -15633,11 +16258,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15633
16258
|
const state = store.getState();
|
|
15634
16259
|
const set = store.setState;
|
|
15635
16260
|
const creator = creatorOrScope;
|
|
15636
|
-
const wrappedState =
|
|
15637
|
-
...state,
|
|
15638
|
-
uniforms: createScopedStore(state.uniforms),
|
|
15639
|
-
nodes: createScopedStore(state.nodes)
|
|
15640
|
-
};
|
|
16261
|
+
const wrappedState = createLazyCreatorState(state);
|
|
15641
16262
|
const created = creator(wrappedState);
|
|
15642
16263
|
const result = {};
|
|
15643
16264
|
let hasNewNodes = false;
|
|
@@ -15647,7 +16268,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15647
16268
|
if (currentScope[name]) {
|
|
15648
16269
|
result[name] = currentScope[name];
|
|
15649
16270
|
} else {
|
|
15650
|
-
|
|
16271
|
+
node.setName?.(`${scope}.${name}`);
|
|
15651
16272
|
result[name] = node;
|
|
15652
16273
|
hasNewNodes = true;
|
|
15653
16274
|
}
|
|
@@ -15667,7 +16288,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15667
16288
|
if (existing && isTSLNode(existing)) {
|
|
15668
16289
|
result[name] = existing;
|
|
15669
16290
|
} else {
|
|
15670
|
-
|
|
16291
|
+
node.setName?.(name);
|
|
15671
16292
|
result[name] = node;
|
|
15672
16293
|
hasNewNodes = true;
|
|
15673
16294
|
}
|
|
@@ -15676,15 +16297,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15676
16297
|
set((s) => ({ nodes: { ...s.nodes, ...result } }));
|
|
15677
16298
|
}
|
|
15678
16299
|
return result;
|
|
15679
|
-
}, [
|
|
15680
|
-
store,
|
|
15681
|
-
typeof creatorOrScope === "string" ? creatorOrScope : scope,
|
|
15682
|
-
// Only include storeNodes in deps for reader modes to enable reactivity
|
|
15683
|
-
// Creator mode intentionally excludes it to avoid re-running creator on unrelated changes
|
|
15684
|
-
isReader ? storeNodes : null,
|
|
15685
|
-
// Include hmrVersion for creator modes to allow rebuildNodes() to bust the cache
|
|
15686
|
-
isReader ? null : hmrVersion
|
|
15687
|
-
]);
|
|
16300
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
15688
16301
|
return { ...nodes, removeNodes: removeNodes2, clearNodes, rebuildNodes };
|
|
15689
16302
|
}
|
|
15690
16303
|
function rebuildAllNodes(store, scope) {
|
|
@@ -15736,15 +16349,11 @@ function useLocalNodes(creator) {
|
|
|
15736
16349
|
const uniforms = useThree((s) => s.uniforms);
|
|
15737
16350
|
const nodes = useThree((s) => s.nodes);
|
|
15738
16351
|
const textures = useThree((s) => s.textures);
|
|
16352
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
15739
16353
|
return useMemo(() => {
|
|
15740
|
-
const
|
|
15741
|
-
const wrappedState = {
|
|
15742
|
-
...state,
|
|
15743
|
-
uniforms: createScopedStore(state.uniforms),
|
|
15744
|
-
nodes: createScopedStore(state.nodes)
|
|
15745
|
-
};
|
|
16354
|
+
const wrappedState = createLazyCreatorState(store.getState());
|
|
15746
16355
|
return creator(wrappedState);
|
|
15747
|
-
}, [store, creator, uniforms, nodes, textures]);
|
|
16356
|
+
}, [store, creator, uniforms, nodes, textures, hmrVersion]);
|
|
15748
16357
|
}
|
|
15749
16358
|
|
|
15750
16359
|
function usePostProcessing(mainCB, setupCB) {
|
|
@@ -15842,4 +16451,4 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
15842
16451
|
|
|
15843
16452
|
extend(THREE);
|
|
15844
16453
|
|
|
15845
|
-
export { Block, Canvas, ErrorBoundary, IsObject, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Scheduler, Texture, _roots, act, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, clearNodeScope, clearRootNodes, clearRootUniforms, clearScope, context, createEvents, createPointerEvents, createPortal, createRoot, createScopedStore, createStore, createTextureOperations, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, getInstanceProps, getRootState, getScheduler, getUuidPrefix, hasConstructor, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isObject3D, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, prepare, rebuildAllNodes, rebuildAllUniforms, reconciler, removeInteractivity, removeNodes, removeUniforms, resolve, unmountComponentAtNode, updateCamera, updateFrustum, useBridge, useFrame, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useLocalNodes, useMutableCallback, useNodes, usePostProcessing, useRenderTarget, useStore, useTexture, useTextures, useThree, useUniform, useUniforms };
|
|
16454
|
+
export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Scheduler, Texture, _roots, act, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, clearNodeScope, clearRootNodes, clearRootUniforms, clearScope, context, createEvents, createPointerEvents, createPortal, createRoot, createScopedStore, createStore, createTextureOperations, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getScheduler, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, rebuildAllNodes, rebuildAllUniforms, reconciler, registerPrimary, removeInteractivity, removeNodes, removeUniforms, resolve, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useEnvironment, useFrame, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useLocalNodes, useMutableCallback, useNodes, usePostProcessing, useRenderTarget, useStore, useTexture, useTextures, useThree, useUniform, useUniforms, waitForPrimary };
|