@react-three/fiber 10.0.0-canary.0d86c23 → 10.0.0-canary.0ea97c0
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/dist/index.cjs +119 -61
- package/dist/index.d.cts +180 -26
- package/dist/index.d.mts +180 -26
- package/dist/index.d.ts +180 -26
- package/dist/index.mjs +119 -61
- package/dist/legacy.cjs +115 -61
- package/dist/legacy.d.cts +179 -29
- package/dist/legacy.d.mts +179 -29
- package/dist/legacy.d.ts +179 -29
- package/dist/legacy.mjs +115 -61
- package/dist/webgpu/index.cjs +182 -98
- package/dist/webgpu/index.d.cts +204 -90
- package/dist/webgpu/index.d.mts +204 -90
- package/dist/webgpu/index.d.ts +204 -90
- package/dist/webgpu/index.mjs +182 -98
- package/package.json +2 -2
- package/readme.md +1 -1
package/dist/webgpu/index.cjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const webgpu = require('three/webgpu');
|
|
4
|
-
const Inspector_js = require('three/addons/inspector/Inspector.js');
|
|
5
4
|
const jsxRuntime = require('react/jsx-runtime');
|
|
6
5
|
const React = require('react');
|
|
7
6
|
const useMeasure = require('react-use-measure');
|
|
@@ -54,6 +53,10 @@ const Tb__default = /*#__PURE__*/_interopDefaultCompat(Tb);
|
|
|
54
53
|
|
|
55
54
|
const R3F_BUILD_LEGACY = false;
|
|
56
55
|
const R3F_BUILD_WEBGPU = true;
|
|
56
|
+
async function loadInspector() {
|
|
57
|
+
const { Inspector } = await import('three/addons/inspector/Inspector.js');
|
|
58
|
+
return Inspector;
|
|
59
|
+
}
|
|
57
60
|
const WebGLRenderer = class WebGLRenderer2 {
|
|
58
61
|
constructor() {
|
|
59
62
|
throw new Error(
|
|
@@ -67,13 +70,13 @@ const WebGLCubeRenderTarget = null;
|
|
|
67
70
|
const THREE = /*#__PURE__*/_mergeNamespaces({
|
|
68
71
|
__proto__: null,
|
|
69
72
|
CubeRenderTargetCompat: webgpu.CubeRenderTarget,
|
|
70
|
-
Inspector: Inspector_js.Inspector,
|
|
71
73
|
R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
|
|
72
74
|
R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
|
|
73
75
|
RenderTargetCompat: webgpu.RenderTarget,
|
|
74
76
|
WebGLCubeRenderTarget: WebGLCubeRenderTarget,
|
|
75
77
|
WebGLRenderTarget: WebGLRenderTarget,
|
|
76
|
-
WebGLRenderer: WebGLRenderer
|
|
78
|
+
WebGLRenderer: WebGLRenderer,
|
|
79
|
+
loadInspector: loadInspector
|
|
77
80
|
}, [webgpu__namespace]);
|
|
78
81
|
|
|
79
82
|
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
@@ -629,7 +632,12 @@ function diffProps(instance, newProps) {
|
|
|
629
632
|
const changedProps = {};
|
|
630
633
|
for (const prop in newProps) {
|
|
631
634
|
if (RESERVED_PROPS.includes(prop)) continue;
|
|
632
|
-
if (is.equ(newProps[prop], instance.props[prop]))
|
|
635
|
+
if (is.equ(newProps[prop], instance.props[prop])) {
|
|
636
|
+
const value = newProps[prop];
|
|
637
|
+
if (!isCopyable(value)) continue;
|
|
638
|
+
const { target } = resolve(instance.object, prop);
|
|
639
|
+
if (!isCopyable(target) || target.constructor !== value.constructor) continue;
|
|
640
|
+
}
|
|
633
641
|
changedProps[prop] = newProps[prop];
|
|
634
642
|
for (const other in newProps) {
|
|
635
643
|
if (other.startsWith(`${prop}-`)) changedProps[other] = newProps[other];
|
|
@@ -932,7 +940,7 @@ const createStore = (invalidate, advance) => {
|
|
|
932
940
|
size: newSize,
|
|
933
941
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
934
942
|
}));
|
|
935
|
-
|
|
943
|
+
get().invalidate();
|
|
936
944
|
}
|
|
937
945
|
}
|
|
938
946
|
return;
|
|
@@ -947,15 +955,16 @@ const createStore = (invalidate, advance) => {
|
|
|
947
955
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
948
956
|
_sizeImperative: true
|
|
949
957
|
}));
|
|
950
|
-
|
|
958
|
+
get().invalidate();
|
|
951
959
|
},
|
|
952
960
|
setDpr: (dpr) => set((state2) => {
|
|
953
961
|
const resolved = calculateDpr(dpr);
|
|
954
962
|
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
955
963
|
}),
|
|
956
964
|
setFrameloop: (frameloop = "always") => {
|
|
965
|
+
const rootId = get().internal.rootId;
|
|
966
|
+
if (rootId) scheduler.getScheduler().setRootFrameloop(rootId, frameloop);
|
|
957
967
|
set(() => ({ frameloop }));
|
|
958
|
-
scheduler.getScheduler().frameloop = frameloop;
|
|
959
968
|
},
|
|
960
969
|
setError: (error) => set(() => ({ error })),
|
|
961
970
|
error: null,
|
|
@@ -1071,17 +1080,11 @@ const createStore = (invalidate, advance) => {
|
|
|
1071
1080
|
oldSize = size;
|
|
1072
1081
|
oldDpr = viewport.dpr;
|
|
1073
1082
|
updateCamera(camera, size);
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
actualRenderer.setSize(size.width, size.height, false);
|
|
1080
|
-
if (canvasTarget) {
|
|
1081
|
-
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
1082
|
-
canvasTarget.setSize(size.width, size.height, false);
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1083
|
+
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
1084
|
+
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
1085
|
+
resizeTarget.setSize(size.width, size.height, false);
|
|
1086
|
+
const activeTarget = actualRenderer.getCanvasTarget?.();
|
|
1087
|
+
if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
|
|
1085
1088
|
}
|
|
1086
1089
|
if (camera !== oldCamera) {
|
|
1087
1090
|
oldCamera = camera;
|
|
@@ -1143,7 +1146,11 @@ function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
|
1143
1146
|
const results = cacheKeys.map(
|
|
1144
1147
|
(key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
1145
1148
|
);
|
|
1146
|
-
|
|
1149
|
+
const stableRef = React.useRef(null);
|
|
1150
|
+
const previous = stableRef.current;
|
|
1151
|
+
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
1152
|
+
stableRef.current = stable;
|
|
1153
|
+
return Array.isArray(input) ? stable : stable[0];
|
|
1147
1154
|
}
|
|
1148
1155
|
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
1149
1156
|
const inputs = Array.isArray(input) ? input : [input];
|
|
@@ -1158,7 +1165,7 @@ useLoader.clear = function(loader, input, cacheKey) {
|
|
|
1158
1165
|
};
|
|
1159
1166
|
useLoader.loader = getLoader$1;
|
|
1160
1167
|
|
|
1161
|
-
function useFrame(callback, priorityOrOptions) {
|
|
1168
|
+
function useFrame$1(callback, priorityOrOptions) {
|
|
1162
1169
|
const store = React__namespace.useContext(context);
|
|
1163
1170
|
const isInsideCanvas = store !== null;
|
|
1164
1171
|
const scheduler$1 = scheduler.getScheduler();
|
|
@@ -1263,6 +1270,13 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1263
1270
|
* Use for controlling the entire frame loop, adding phases, etc.
|
|
1264
1271
|
*/
|
|
1265
1272
|
scheduler: scheduler2,
|
|
1273
|
+
/**
|
|
1274
|
+
* The root that currently owns this job. Resolve on access because ambient
|
|
1275
|
+
* jobs can be adopted by a Canvas after the controls object is created.
|
|
1276
|
+
*/
|
|
1277
|
+
get rootId() {
|
|
1278
|
+
return scheduler.getScheduler().getJobRootId(id);
|
|
1279
|
+
},
|
|
1266
1280
|
/**
|
|
1267
1281
|
* Manually step this job only.
|
|
1268
1282
|
* Bypasses FPS limiting - always runs.
|
|
@@ -1279,6 +1293,14 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1279
1293
|
stepAll: (timestamp) => {
|
|
1280
1294
|
scheduler.getScheduler().step(timestamp);
|
|
1281
1295
|
},
|
|
1296
|
+
/**
|
|
1297
|
+
* Request frames for this job's owning root without waking sibling roots.
|
|
1298
|
+
*/
|
|
1299
|
+
invalidate: (frames, stackFrames) => {
|
|
1300
|
+
const scheduler3 = scheduler.getScheduler();
|
|
1301
|
+
const rootId = scheduler3.getJobRootId(id);
|
|
1302
|
+
if (rootId) scheduler3.invalidateRoot(rootId, frames, stackFrames);
|
|
1303
|
+
},
|
|
1282
1304
|
/**
|
|
1283
1305
|
* Pause this job (set enabled=false).
|
|
1284
1306
|
* Job remains registered but won't run.
|
|
@@ -1308,6 +1330,11 @@ function getUrls(input) {
|
|
|
1308
1330
|
if (Array.isArray(input)) return input;
|
|
1309
1331
|
return Object.values(input);
|
|
1310
1332
|
}
|
|
1333
|
+
function inputSignature(input) {
|
|
1334
|
+
if (typeof input === "string") return input;
|
|
1335
|
+
if (Array.isArray(input)) return input.join("\0");
|
|
1336
|
+
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
1337
|
+
}
|
|
1311
1338
|
function allUrlsCached(urls, textureCache) {
|
|
1312
1339
|
return urls.every((url) => textureCache.has(url));
|
|
1313
1340
|
}
|
|
@@ -1326,25 +1353,26 @@ function buildFromCache(input, textureCache) {
|
|
|
1326
1353
|
}
|
|
1327
1354
|
}
|
|
1328
1355
|
function useTexture(input, optionsOrOnLoad) {
|
|
1329
|
-
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
1356
|
+
const renderer = useThree$1((state) => state.internal.actualRenderer);
|
|
1330
1357
|
const store = useStore();
|
|
1331
1358
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
1332
1359
|
const { onLoad, cache = true } = options;
|
|
1333
1360
|
const onLoadRef = React.useRef(onLoad);
|
|
1334
1361
|
onLoadRef.current = onLoad;
|
|
1335
1362
|
const onLoadCalledForRef = React.useRef(null);
|
|
1336
|
-
const
|
|
1363
|
+
const inputKey = React.useMemo(() => inputSignature(input), [input]);
|
|
1364
|
+
const stableInput = React.useMemo(() => input, [inputKey]);
|
|
1365
|
+
const urls = React.useMemo(() => getUrls(stableInput), [stableInput]);
|
|
1337
1366
|
const cachedResult = React.useMemo(() => {
|
|
1338
1367
|
if (!cache) return null;
|
|
1339
1368
|
const textures = store.getState().textures;
|
|
1340
1369
|
if (!allUrlsCached(urls, textures)) return null;
|
|
1341
|
-
return buildFromCache(
|
|
1342
|
-
}, [cache, urls,
|
|
1370
|
+
return buildFromCache(stableInput, textures);
|
|
1371
|
+
}, [cache, urls, stableInput, store]);
|
|
1343
1372
|
const loadedTextures = useLoader(
|
|
1344
1373
|
webgpu.TextureLoader,
|
|
1345
|
-
IsObject(
|
|
1374
|
+
IsObject(stableInput) ? Object.values(stableInput) : stableInput
|
|
1346
1375
|
);
|
|
1347
|
-
const inputKey = urls.join("\0");
|
|
1348
1376
|
React.useLayoutEffect(() => {
|
|
1349
1377
|
if (cachedResult) return;
|
|
1350
1378
|
if (onLoadCalledForRef.current === inputKey) return;
|
|
@@ -1371,28 +1399,28 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1371
1399
|
}, [renderer, loadedTextures, cachedResult]);
|
|
1372
1400
|
const mappedTextures = React.useMemo(() => {
|
|
1373
1401
|
if (cachedResult) return cachedResult;
|
|
1374
|
-
if (IsObject(
|
|
1402
|
+
if (IsObject(stableInput)) {
|
|
1375
1403
|
const keyed = {};
|
|
1376
1404
|
const textureArray = loadedTextures;
|
|
1377
1405
|
let i = 0;
|
|
1378
|
-
for (const key in
|
|
1406
|
+
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
1379
1407
|
return keyed;
|
|
1380
1408
|
} else {
|
|
1381
1409
|
return loadedTextures;
|
|
1382
1410
|
}
|
|
1383
|
-
}, [
|
|
1411
|
+
}, [stableInput, loadedTextures, cachedResult]);
|
|
1384
1412
|
React.useEffect(() => {
|
|
1385
1413
|
if (!cache) return;
|
|
1386
1414
|
const urlTextureMap = [];
|
|
1387
|
-
if (typeof
|
|
1388
|
-
urlTextureMap.push([
|
|
1389
|
-
} else if (Array.isArray(
|
|
1415
|
+
if (typeof stableInput === "string") {
|
|
1416
|
+
urlTextureMap.push([stableInput, mappedTextures]);
|
|
1417
|
+
} else if (Array.isArray(stableInput)) {
|
|
1390
1418
|
const textureArray = mappedTextures;
|
|
1391
|
-
|
|
1392
|
-
} else if (IsObject(
|
|
1419
|
+
stableInput.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
|
|
1420
|
+
} else if (IsObject(stableInput)) {
|
|
1393
1421
|
const textureRecord = mappedTextures;
|
|
1394
|
-
for (const key in
|
|
1395
|
-
const url =
|
|
1422
|
+
for (const key in stableInput) {
|
|
1423
|
+
const url = stableInput[key];
|
|
1396
1424
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
1397
1425
|
}
|
|
1398
1426
|
}
|
|
@@ -1421,7 +1449,7 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1421
1449
|
}
|
|
1422
1450
|
return { _textureRefs: refs };
|
|
1423
1451
|
});
|
|
1424
|
-
}, [cache,
|
|
1452
|
+
}, [cache, stableInput, mappedTextures, store]);
|
|
1425
1453
|
return mappedTextures;
|
|
1426
1454
|
}
|
|
1427
1455
|
useTexture.preload = (url) => useLoader.preload(webgpu.TextureLoader, url);
|
|
@@ -1492,13 +1520,13 @@ function useTextures(selector) {
|
|
|
1492
1520
|
};
|
|
1493
1521
|
}, [store]);
|
|
1494
1522
|
const subscribe = selector ? () => selector(registry) : (state) => state.textures;
|
|
1495
|
-
const selected = useThree(subscribe);
|
|
1523
|
+
const selected = useThree$1(subscribe);
|
|
1496
1524
|
return selector ? selected : registry;
|
|
1497
1525
|
}
|
|
1498
1526
|
|
|
1499
1527
|
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
1500
|
-
const isLegacy = useThree((s) => s.isLegacy);
|
|
1501
|
-
const size = useThree((s) => s.size);
|
|
1528
|
+
const isLegacy = useThree$1((s) => s.isLegacy);
|
|
1529
|
+
const size = useThree$1((s) => s.size);
|
|
1502
1530
|
let width;
|
|
1503
1531
|
let height;
|
|
1504
1532
|
let opts;
|
|
@@ -1555,7 +1583,7 @@ function useEnvironment({
|
|
|
1555
1583
|
const { extension, isCubemap } = getExtension(files);
|
|
1556
1584
|
const loader = getLoader(extension);
|
|
1557
1585
|
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
1558
|
-
const renderer = useThree((state) => state.renderer);
|
|
1586
|
+
const renderer = useThree$1((state) => state.renderer);
|
|
1559
1587
|
React.useLayoutEffect(() => {
|
|
1560
1588
|
if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
|
|
1561
1589
|
function clearGainmapTexture() {
|
|
@@ -1648,7 +1676,7 @@ function useStore() {
|
|
|
1648
1676
|
if (!store) throw new Error("R3F: Hooks can only be used within the Canvas component!");
|
|
1649
1677
|
return store;
|
|
1650
1678
|
}
|
|
1651
|
-
function useThree(selector = (state) => state, equalityFn) {
|
|
1679
|
+
function useThree$1(selector = (state) => state, equalityFn) {
|
|
1652
1680
|
return useStore()(selector, equalityFn);
|
|
1653
1681
|
}
|
|
1654
1682
|
function useInstanceHandle(ref) {
|
|
@@ -1690,13 +1718,19 @@ function addTail(callback) {
|
|
|
1690
1718
|
return scheduler.getScheduler().onIdle(callback);
|
|
1691
1719
|
}
|
|
1692
1720
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
1693
|
-
|
|
1721
|
+
const rootId = state?.internal?.rootId;
|
|
1722
|
+
const scheduler$1 = scheduler.getScheduler();
|
|
1723
|
+
if (rootId) scheduler$1.invalidateRoot(rootId, frames, stackFrames);
|
|
1724
|
+
else scheduler$1.invalidate(frames, stackFrames);
|
|
1694
1725
|
}
|
|
1695
|
-
function advance(timestamp) {
|
|
1696
|
-
|
|
1726
|
+
function advance(timestamp, runGlobalEffects, state) {
|
|
1727
|
+
const rootId = state?.internal?.rootId;
|
|
1728
|
+
const scheduler$1 = scheduler.getScheduler();
|
|
1729
|
+
if (rootId) scheduler$1.stepRoot(rootId, timestamp);
|
|
1730
|
+
else scheduler$1.step(timestamp);
|
|
1697
1731
|
}
|
|
1698
1732
|
|
|
1699
|
-
const version = "10.0.0-alpha.
|
|
1733
|
+
const version = "10.0.0-alpha.4";
|
|
1700
1734
|
const packageData = {
|
|
1701
1735
|
version: version};
|
|
1702
1736
|
|
|
@@ -14212,9 +14246,8 @@ function createRoot(canvas) {
|
|
|
14212
14246
|
if (!renderer.hasInitialized?.()) {
|
|
14213
14247
|
const size2 = computeInitialSize(canvas, propsSize);
|
|
14214
14248
|
if (size2.width > 0 && size2.height > 0) {
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
canvas.height = size2.height * pixelRatio;
|
|
14249
|
+
renderer.setPixelRatio(calculateDpr(dpr));
|
|
14250
|
+
renderer.setSize(size2.width, size2.height, false);
|
|
14218
14251
|
}
|
|
14219
14252
|
await renderer.init();
|
|
14220
14253
|
}
|
|
@@ -14223,7 +14256,7 @@ function createRoot(canvas) {
|
|
|
14223
14256
|
state.internal.actualRenderer = renderer;
|
|
14224
14257
|
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
14225
14258
|
if (canvasId && !state.internal.isSecondary) {
|
|
14226
|
-
const canvasTarget =
|
|
14259
|
+
const canvasTarget = renderer.getCanvasTarget?.();
|
|
14227
14260
|
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
14228
14261
|
state.set((prev) => ({
|
|
14229
14262
|
internal: {
|
|
@@ -14337,7 +14370,7 @@ function createRoot(canvas) {
|
|
|
14337
14370
|
const handleXRFrame = (timestamp, _frame) => {
|
|
14338
14371
|
const state2 = store.getState();
|
|
14339
14372
|
if (state2.frameloop === "never") return;
|
|
14340
|
-
advance(timestamp);
|
|
14373
|
+
advance(timestamp, true, state2);
|
|
14341
14374
|
};
|
|
14342
14375
|
const actualRenderer = state.internal.actualRenderer;
|
|
14343
14376
|
const handleSessionChange = () => {
|
|
@@ -14345,7 +14378,7 @@ function createRoot(canvas) {
|
|
|
14345
14378
|
const renderer2 = state2.internal.actualRenderer;
|
|
14346
14379
|
actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
|
|
14347
14380
|
renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
|
|
14348
|
-
if (!renderer2.xr.isPresenting) invalidate();
|
|
14381
|
+
if (!renderer2.xr.isPresenting) invalidate(state2);
|
|
14349
14382
|
};
|
|
14350
14383
|
const xr = {
|
|
14351
14384
|
connect() {
|
|
@@ -14427,14 +14460,23 @@ function createRoot(canvas) {
|
|
|
14427
14460
|
const newRootId = canvasId || scheduler$1.generateRootId();
|
|
14428
14461
|
const unregisterRoot = scheduler$1.registerRoot(newRootId, {
|
|
14429
14462
|
getState: () => store.getState(),
|
|
14430
|
-
onError: (err) => store.getState().setError(err)
|
|
14463
|
+
onError: (err) => store.getState().setError(err),
|
|
14464
|
+
frameloop: store.getState().frameloop,
|
|
14465
|
+
before: schedulerConfig?.before,
|
|
14466
|
+
after: schedulerConfig?.after,
|
|
14467
|
+
order: schedulerConfig?.order
|
|
14431
14468
|
});
|
|
14432
14469
|
const unregisterCanvasTarget = scheduler$1.register(
|
|
14433
14470
|
() => {
|
|
14434
14471
|
const state2 = store.getState();
|
|
14435
|
-
|
|
14472
|
+
const canvasTarget = state2.internal.canvasTarget;
|
|
14473
|
+
if (canvasTarget) {
|
|
14436
14474
|
const renderer2 = state2.internal.actualRenderer;
|
|
14437
|
-
renderer2.setCanvasTarget(
|
|
14475
|
+
if (renderer2.getCanvasTarget() !== canvasTarget) renderer2.setCanvasTarget(canvasTarget);
|
|
14476
|
+
if (state2.internal.canvasTargetSizeDirty) {
|
|
14477
|
+
state2.internal.canvasTargetSizeDirty = false;
|
|
14478
|
+
renderer2.backend?.updateSize?.();
|
|
14479
|
+
}
|
|
14438
14480
|
}
|
|
14439
14481
|
},
|
|
14440
14482
|
{
|
|
@@ -14503,8 +14545,7 @@ function createRoot(canvas) {
|
|
|
14503
14545
|
phase: "render",
|
|
14504
14546
|
system: true,
|
|
14505
14547
|
// Internal flag: this is a system job, not user-controlled
|
|
14506
|
-
//
|
|
14507
|
-
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
14548
|
+
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
14508
14549
|
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14509
14550
|
}
|
|
14510
14551
|
);
|
|
@@ -14523,8 +14564,21 @@ function createRoot(canvas) {
|
|
|
14523
14564
|
scheduler: scheduler$1
|
|
14524
14565
|
}
|
|
14525
14566
|
}));
|
|
14567
|
+
} else {
|
|
14568
|
+
const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
|
|
14569
|
+
if (constraintsChanged) {
|
|
14570
|
+
scheduler$1.setRootConstraints(rootId, {
|
|
14571
|
+
before: schedulerConfig?.before,
|
|
14572
|
+
after: schedulerConfig?.after
|
|
14573
|
+
});
|
|
14574
|
+
}
|
|
14575
|
+
if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
|
|
14576
|
+
scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
14577
|
+
}
|
|
14526
14578
|
}
|
|
14527
|
-
|
|
14579
|
+
lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
|
|
14580
|
+
lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
|
|
14581
|
+
lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
|
|
14528
14582
|
onCreated = onCreatedCallback;
|
|
14529
14583
|
configured = true;
|
|
14530
14584
|
resolve();
|
|
@@ -14566,18 +14620,23 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14566
14620
|
const fiber = root?.fiber;
|
|
14567
14621
|
if (fiber) {
|
|
14568
14622
|
const state = root?.store.getState();
|
|
14569
|
-
if (state)
|
|
14623
|
+
if (state) {
|
|
14624
|
+
state.internal.active = false;
|
|
14625
|
+
const unregisterRoot = state.internal.unregisterRoot;
|
|
14626
|
+
if (unregisterRoot) {
|
|
14627
|
+
unregisterRoot();
|
|
14628
|
+
state.internal.unregisterRoot = void 0;
|
|
14629
|
+
}
|
|
14630
|
+
}
|
|
14570
14631
|
reconciler.updateContainer(null, fiber, null, () => {
|
|
14571
14632
|
if (state) {
|
|
14572
14633
|
setTimeout(() => {
|
|
14573
14634
|
try {
|
|
14574
14635
|
const renderer = state.internal.actualRenderer;
|
|
14575
|
-
const unregisterRoot = state.internal.unregisterRoot;
|
|
14576
|
-
if (unregisterRoot) unregisterRoot();
|
|
14577
14636
|
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
14578
14637
|
if (unregisterPrimary) unregisterPrimary();
|
|
14579
14638
|
const canvasTarget = state.internal.canvasTarget;
|
|
14580
|
-
if (canvasTarget?.dispose) canvasTarget.dispose();
|
|
14639
|
+
if (state.internal.isSecondary && canvasTarget?.dispose) canvasTarget.dispose();
|
|
14581
14640
|
state.events.disconnect?.();
|
|
14582
14641
|
cleanupHelperGroup(root.store);
|
|
14583
14642
|
if (state.isLegacy && renderer) {
|
|
@@ -14739,7 +14798,7 @@ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {})
|
|
|
14739
14798
|
};
|
|
14740
14799
|
}
|
|
14741
14800
|
function EnvironmentMap({ scene, background = false, map, ...config }) {
|
|
14742
|
-
const defaultScene = useThree((state) => state.scene);
|
|
14801
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
14743
14802
|
React__namespace.useLayoutEffect(() => {
|
|
14744
14803
|
if (map) return setEnvProps(background, scene, defaultScene, map, config);
|
|
14745
14804
|
});
|
|
@@ -14757,7 +14816,7 @@ function EnvironmentCube({
|
|
|
14757
14816
|
...rest
|
|
14758
14817
|
}) {
|
|
14759
14818
|
const texture = useEnvironment(rest);
|
|
14760
|
-
const defaultScene = useThree((state) => state.scene);
|
|
14819
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
14761
14820
|
React__namespace.useLayoutEffect(() => {
|
|
14762
14821
|
return setEnvProps(background, scene, defaultScene, texture, {
|
|
14763
14822
|
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
@@ -14794,9 +14853,9 @@ function EnvironmentPortal({
|
|
|
14794
14853
|
preset = void 0,
|
|
14795
14854
|
extensions
|
|
14796
14855
|
}) {
|
|
14797
|
-
const renderer = useThree((state) => state.renderer);
|
|
14798
|
-
const isLegacy = useThree((state) => state.isLegacy);
|
|
14799
|
-
const defaultScene = useThree((state) => state.scene);
|
|
14856
|
+
const renderer = useThree$1((state) => state.renderer);
|
|
14857
|
+
const isLegacy = useThree$1((state) => state.isLegacy);
|
|
14858
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
14800
14859
|
const camera = React__namespace.useRef(null);
|
|
14801
14860
|
const [virtualScene] = React__namespace.useState(() => new webgpu.Scene());
|
|
14802
14861
|
const fbo = React__namespace.useMemo(() => {
|
|
@@ -14840,7 +14899,7 @@ function EnvironmentPortal({
|
|
|
14840
14899
|
environmentRotation
|
|
14841
14900
|
]);
|
|
14842
14901
|
let count = 1;
|
|
14843
|
-
useFrame(() => {
|
|
14902
|
+
useFrame$1(() => {
|
|
14844
14903
|
if (frames === Infinity || count < frames) {
|
|
14845
14904
|
const autoClear = renderer.autoClear;
|
|
14846
14905
|
renderer.autoClear = true;
|
|
@@ -14880,7 +14939,7 @@ function EnvironmentGround(props) {
|
|
|
14880
14939
|
] });
|
|
14881
14940
|
}
|
|
14882
14941
|
function EnvironmentColor({ color, scene }) {
|
|
14883
|
-
const defaultScene = useThree((state) => state.scene);
|
|
14942
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
14884
14943
|
React__namespace.useLayoutEffect(() => {
|
|
14885
14944
|
if (color === void 0) return;
|
|
14886
14945
|
const target = resolveScene(scene || defaultScene);
|
|
@@ -15118,9 +15177,9 @@ function CanvasImpl({
|
|
|
15118
15177
|
React__namespace.useMemo(() => extend(THREE), []);
|
|
15119
15178
|
const Bridge = useBridge();
|
|
15120
15179
|
const backgroundProps = React__namespace.useMemo(() => parseBackground(background), [background]);
|
|
15121
|
-
const
|
|
15180
|
+
const [hasInitialSize, setHasInitialSize] = React__namespace.useState(false);
|
|
15122
15181
|
const measureConfig = React__namespace.useMemo(() => {
|
|
15123
|
-
if (!
|
|
15182
|
+
if (!hasInitialSize) {
|
|
15124
15183
|
return {
|
|
15125
15184
|
...resize,
|
|
15126
15185
|
scroll: resize?.scroll ?? true,
|
|
@@ -15132,7 +15191,7 @@ function CanvasImpl({
|
|
|
15132
15191
|
debounce: { scroll: 50, resize: 0 },
|
|
15133
15192
|
...resize
|
|
15134
15193
|
};
|
|
15135
|
-
}, [
|
|
15194
|
+
}, [hasInitialSize, resize]);
|
|
15136
15195
|
const [containerRef, containerRect] = useMeasure__default(measureConfig);
|
|
15137
15196
|
const effectiveSize = React__namespace.useMemo(() => {
|
|
15138
15197
|
let w = width ?? containerRect.width;
|
|
@@ -15148,9 +15207,7 @@ function CanvasImpl({
|
|
|
15148
15207
|
left: containerRect.left
|
|
15149
15208
|
};
|
|
15150
15209
|
}, [width, height, containerRect, forceEven]);
|
|
15151
|
-
if (!
|
|
15152
|
-
hasInitialSizeRef.current = true;
|
|
15153
|
-
}
|
|
15210
|
+
if (!hasInitialSize && effectiveSize.width > 0 && effectiveSize.height > 0) setHasInitialSize(true);
|
|
15154
15211
|
const canvasRef = React__namespace.useRef(null);
|
|
15155
15212
|
const divRef = React__namespace.useRef(null);
|
|
15156
15213
|
React__namespace.useImperativeHandle(ref, () => canvasRef.current);
|
|
@@ -15264,6 +15321,7 @@ function CanvasImpl({
|
|
|
15264
15321
|
const canvas = canvasRef.current;
|
|
15265
15322
|
if (canvas) {
|
|
15266
15323
|
return () => {
|
|
15324
|
+
if (canvas.isConnected) return;
|
|
15267
15325
|
unmountComponentAtNode(canvas);
|
|
15268
15326
|
root.current = null;
|
|
15269
15327
|
};
|
|
@@ -15474,6 +15532,11 @@ function createTextureOperations(set) {
|
|
|
15474
15532
|
removeMultiple: (keys) => removeTextures(set, keys)
|
|
15475
15533
|
};
|
|
15476
15534
|
}
|
|
15535
|
+
function scopedNodeName(scope, name) {
|
|
15536
|
+
const raw = scope ? `${scope}_${name}` : name;
|
|
15537
|
+
const safe = raw.replace(/[^A-Za-z0-9_]/g, "_");
|
|
15538
|
+
return /^[A-Za-z_]/.test(safe) ? safe : `_${safe}`;
|
|
15539
|
+
}
|
|
15477
15540
|
function extractTSLValue(value) {
|
|
15478
15541
|
if (value === null || value === void 0) return value;
|
|
15479
15542
|
if (typeof value !== "object") return value;
|
|
@@ -15672,8 +15735,7 @@ function createUniform(inName, node, scope) {
|
|
|
15672
15735
|
const inValue = vectorize(node);
|
|
15673
15736
|
const newUniform = tsl.uniform(inValue);
|
|
15674
15737
|
if (typeof newUniform.setName === "function") {
|
|
15675
|
-
|
|
15676
|
-
newUniform.setName(name);
|
|
15738
|
+
newUniform.setName(scopedNodeName(scope, inName));
|
|
15677
15739
|
}
|
|
15678
15740
|
return newUniform;
|
|
15679
15741
|
}
|
|
@@ -15772,7 +15834,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15772
15834
|
return creatorOrScope(createLazyCreatorState(store.getState(), store));
|
|
15773
15835
|
},
|
|
15774
15836
|
prepare: (name, node) => {
|
|
15775
|
-
node.setName?.(scope
|
|
15837
|
+
node.setName?.(scopedNodeName(scope, name));
|
|
15776
15838
|
return node;
|
|
15777
15839
|
}
|
|
15778
15840
|
});
|
|
@@ -15881,7 +15943,7 @@ function useBuffers(creatorOrScope, scope) {
|
|
|
15881
15943
|
},
|
|
15882
15944
|
prepare: (name, buffer) => {
|
|
15883
15945
|
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
15884
|
-
buffer.setName(scope
|
|
15946
|
+
buffer.setName(scopedNodeName(scope, name));
|
|
15885
15947
|
}
|
|
15886
15948
|
return buffer;
|
|
15887
15949
|
}
|
|
@@ -15952,7 +16014,7 @@ function useGPUStorage(creatorOrScope, scope) {
|
|
|
15952
16014
|
return creatorOrScope(createLazyCreatorState(store.getState(), store));
|
|
15953
16015
|
},
|
|
15954
16016
|
prepare: (name, storage) => {
|
|
15955
|
-
const label = scope
|
|
16017
|
+
const label = scopedNodeName(scope, name);
|
|
15956
16018
|
if ("setName" in storage && typeof storage.setName === "function") {
|
|
15957
16019
|
storage.setName(label);
|
|
15958
16020
|
}
|
|
@@ -15983,9 +16045,10 @@ function rebuildAllStorage(store, scope) {
|
|
|
15983
16045
|
|
|
15984
16046
|
function useRenderPipeline(mainCB, setupCB) {
|
|
15985
16047
|
const store = useStore();
|
|
15986
|
-
const { scene, camera, renderer, isLegacy } = useThree();
|
|
16048
|
+
const { scene, camera, renderer, isLegacy } = useThree$1();
|
|
15987
16049
|
const callbacksRanRef = React.useRef(false);
|
|
15988
16050
|
const scenePassCacheRef = React.useRef(null);
|
|
16051
|
+
const forceScenePassRebuildRef = React.useRef(false);
|
|
15989
16052
|
const mainCBRef = React.useRef(mainCB);
|
|
15990
16053
|
const setupCBRef = React.useRef(setupCB);
|
|
15991
16054
|
mainCBRef.current = mainCB;
|
|
@@ -15993,7 +16056,7 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
15993
16056
|
const [rebuildVersion, setRebuildVersion] = React.useState(0);
|
|
15994
16057
|
React.useEffect(() => {
|
|
15995
16058
|
callbacksRanRef.current = false;
|
|
15996
|
-
|
|
16059
|
+
forceScenePassRebuildRef.current = true;
|
|
15997
16060
|
}, []);
|
|
15998
16061
|
const clearPasses = React.useCallback(() => {
|
|
15999
16062
|
store.setState({ passes: {} });
|
|
@@ -16003,12 +16066,14 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
16003
16066
|
renderPipeline: null,
|
|
16004
16067
|
passes: {}
|
|
16005
16068
|
});
|
|
16069
|
+
scenePassCacheRef.current?.scenePass.dispose();
|
|
16006
16070
|
callbacksRanRef.current = false;
|
|
16007
16071
|
scenePassCacheRef.current = null;
|
|
16072
|
+
forceScenePassRebuildRef.current = false;
|
|
16008
16073
|
}, [store]);
|
|
16009
16074
|
const rebuild = React.useCallback(() => {
|
|
16010
16075
|
callbacksRanRef.current = false;
|
|
16011
|
-
|
|
16076
|
+
forceScenePassRebuildRef.current = true;
|
|
16012
16077
|
setRebuildVersion((v) => v + 1);
|
|
16013
16078
|
}, []);
|
|
16014
16079
|
React.useLayoutEffect(() => {
|
|
@@ -16016,6 +16081,9 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
16016
16081
|
throw new Error("useRenderPipeline is only available with WebGPU renderer. Set renderer prop on Canvas.");
|
|
16017
16082
|
}
|
|
16018
16083
|
if (!renderer || !scene || !camera) return;
|
|
16084
|
+
if (!("isWebGPURenderer" in renderer)) {
|
|
16085
|
+
throw new Error("useRenderPipeline: renderer is not a WebGPURenderer but isLegacy is false.");
|
|
16086
|
+
}
|
|
16019
16087
|
const state = store.getState();
|
|
16020
16088
|
const set = store.setState;
|
|
16021
16089
|
try {
|
|
@@ -16026,21 +16094,33 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
16026
16094
|
pipeline = new webgpu.RenderPipeline(renderer);
|
|
16027
16095
|
justCreatedPipeline = true;
|
|
16028
16096
|
}
|
|
16029
|
-
const cacheValid = scenePassCacheRef.current && scenePassCacheRef.current.sceneUuid === scene.uuid && scenePassCacheRef.current.cameraUuid === camera.uuid;
|
|
16097
|
+
const cacheValid = !forceScenePassRebuildRef.current && scenePassCacheRef.current && scenePassCacheRef.current.sceneUuid === scene.uuid && scenePassCacheRef.current.cameraUuid === camera.uuid;
|
|
16098
|
+
let outgoingScenePass = null;
|
|
16030
16099
|
let scenePass;
|
|
16031
16100
|
if (cacheValid) {
|
|
16032
16101
|
scenePass = scenePassCacheRef.current.scenePass;
|
|
16033
16102
|
} else {
|
|
16103
|
+
outgoingScenePass = scenePassCacheRef.current?.scenePass ?? null;
|
|
16034
16104
|
scenePass = tsl.pass(scene, camera);
|
|
16035
16105
|
scenePassCacheRef.current = { sceneUuid: scene.uuid, cameraUuid: camera.uuid, scenePass };
|
|
16106
|
+
forceScenePassRebuildRef.current = false;
|
|
16036
16107
|
}
|
|
16037
16108
|
currentPasses.scenePass = scenePass;
|
|
16038
|
-
|
|
16109
|
+
let outputNodeChanged = false;
|
|
16110
|
+
if (!pipeline.outputNode || justCreatedPipeline || pipeline.outputNode === outgoingScenePass) {
|
|
16111
|
+
pipeline.outputNode = scenePass;
|
|
16112
|
+
outputNodeChanged = true;
|
|
16113
|
+
}
|
|
16039
16114
|
set({ renderPipeline: pipeline, passes: currentPasses });
|
|
16040
16115
|
const shouldRunCallbacks = justCreatedPipeline || !callbacksRanRef.current || !cacheValid;
|
|
16041
16116
|
if (shouldRunCallbacks) {
|
|
16042
16117
|
if (setupCBRef.current) {
|
|
16043
|
-
const freshState = store.getState()
|
|
16118
|
+
const freshState = Object.assign({}, store.getState(), {
|
|
16119
|
+
renderPipeline: pipeline,
|
|
16120
|
+
passes: { ...currentPasses, scenePass },
|
|
16121
|
+
renderer,
|
|
16122
|
+
isLegacy: false
|
|
16123
|
+
});
|
|
16044
16124
|
const setupResult = setupCBRef.current(freshState);
|
|
16045
16125
|
if (setupResult && typeof setupResult === "object") {
|
|
16046
16126
|
currentPasses = { ...currentPasses, ...setupResult };
|
|
@@ -16048,33 +16128,37 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
16048
16128
|
}
|
|
16049
16129
|
}
|
|
16050
16130
|
if (mainCBRef.current) {
|
|
16051
|
-
const freshState = store.getState()
|
|
16131
|
+
const freshState = Object.assign({}, store.getState(), {
|
|
16132
|
+
renderPipeline: pipeline,
|
|
16133
|
+
passes: { ...currentPasses, scenePass },
|
|
16134
|
+
renderer,
|
|
16135
|
+
isLegacy: false
|
|
16136
|
+
});
|
|
16052
16137
|
const mainResult = mainCBRef.current(freshState);
|
|
16053
16138
|
if (mainResult && typeof mainResult === "object") {
|
|
16054
16139
|
currentPasses = { ...currentPasses, ...mainResult };
|
|
16055
16140
|
set({ passes: currentPasses });
|
|
16056
16141
|
}
|
|
16057
16142
|
}
|
|
16143
|
+
outputNodeChanged = true;
|
|
16058
16144
|
callbacksRanRef.current = true;
|
|
16059
16145
|
}
|
|
16146
|
+
if (outputNodeChanged) pipeline.needsUpdate = true;
|
|
16147
|
+
if (outgoingScenePass && outgoingScenePass !== scenePass) outgoingScenePass.dispose();
|
|
16060
16148
|
} catch (error) {
|
|
16061
16149
|
console.warn("[useRenderPipeline] Setup failed; the render pipeline was not configured:", error);
|
|
16062
16150
|
}
|
|
16063
16151
|
}, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
|
|
16064
|
-
const passes = useThree((s) => s.passes);
|
|
16065
|
-
const renderPipeline = useThree((s) => s.renderPipeline);
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
clearPasses,
|
|
16070
|
-
reset,
|
|
16071
|
-
rebuild,
|
|
16072
|
-
// isReady indicates if RenderPipeline is configured and ready for rendering
|
|
16073
|
-
isReady: renderPipeline !== null
|
|
16074
|
-
};
|
|
16152
|
+
const passes = useThree$1((s) => s.passes);
|
|
16153
|
+
const renderPipeline = useThree$1((s) => s.renderPipeline);
|
|
16154
|
+
const actions = { passes, clearPasses, reset, rebuild };
|
|
16155
|
+
if (renderPipeline) return { ...actions, isReady: true, renderPipeline };
|
|
16156
|
+
return { ...actions, isReady: false, renderPipeline: null };
|
|
16075
16157
|
}
|
|
16076
16158
|
|
|
16077
16159
|
extend(THREE);
|
|
16160
|
+
const useThree = useThree$1;
|
|
16161
|
+
const useFrame = useFrame$1;
|
|
16078
16162
|
|
|
16079
16163
|
exports.Scheduler = scheduler.Scheduler;
|
|
16080
16164
|
exports.getScheduler = scheduler.getScheduler;
|