@react-three/fiber 10.0.0-canary.b0fafc8 → 10.0.0-canary.d6fdf72
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 +440 -188
- package/dist/index.d.cts +236 -80
- package/dist/index.d.mts +236 -80
- package/dist/index.d.ts +236 -80
- package/dist/index.mjs +441 -189
- package/dist/legacy.cjs +434 -188
- package/dist/legacy.d.cts +236 -80
- package/dist/legacy.d.mts +236 -80
- package/dist/legacy.d.ts +236 -80
- package/dist/legacy.mjs +435 -189
- package/dist/webgpu/index.cjs +815 -199
- package/dist/webgpu/index.d.cts +321 -93
- package/dist/webgpu/index.d.mts +321 -93
- package/dist/webgpu/index.d.ts +321 -93
- package/dist/webgpu/index.mjs +812 -200
- package/package.json +1 -1
package/dist/webgpu/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as webgpu from 'three/webgpu';
|
|
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,
|
|
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, PCFShadowMap, VSMShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGPURenderer, Vector4, PostProcessing } from 'three/webgpu';
|
|
3
3
|
import { Inspector } from 'three/addons/inspector/Inspector.js';
|
|
4
4
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
5
5
|
import * as React from 'react';
|
|
@@ -149,7 +149,7 @@ function useEnvironment({
|
|
|
149
149
|
useLoader$1.clear(loader, multiFile ? [files] : files);
|
|
150
150
|
}
|
|
151
151
|
renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
|
|
152
|
-
}, [files, renderer.domElement]);
|
|
152
|
+
}, [extension, files, loader, multiFile, renderer.domElement]);
|
|
153
153
|
const loaderResult = useLoader$1(
|
|
154
154
|
loader,
|
|
155
155
|
multiFile ? [files] : files,
|
|
@@ -349,7 +349,22 @@ function EnvironmentPortal({
|
|
|
349
349
|
environmentIntensity,
|
|
350
350
|
environmentRotation
|
|
351
351
|
});
|
|
352
|
-
}, [
|
|
352
|
+
}, [
|
|
353
|
+
children,
|
|
354
|
+
virtualScene,
|
|
355
|
+
fbo.texture,
|
|
356
|
+
scene,
|
|
357
|
+
defaultScene,
|
|
358
|
+
background,
|
|
359
|
+
frames,
|
|
360
|
+
gl,
|
|
361
|
+
blur,
|
|
362
|
+
backgroundBlurriness,
|
|
363
|
+
backgroundIntensity,
|
|
364
|
+
backgroundRotation,
|
|
365
|
+
environmentIntensity,
|
|
366
|
+
environmentRotation
|
|
367
|
+
]);
|
|
353
368
|
let count = 1;
|
|
354
369
|
useFrame$1(() => {
|
|
355
370
|
if (frames === Infinity || count < frames) {
|
|
@@ -985,6 +1000,9 @@ function applyProps(object, props) {
|
|
|
985
1000
|
else target.set(value);
|
|
986
1001
|
} else {
|
|
987
1002
|
root[key] = value;
|
|
1003
|
+
if (key.endsWith("Node") && root.isMaterial) {
|
|
1004
|
+
root.needsUpdate = true;
|
|
1005
|
+
}
|
|
988
1006
|
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
|
|
989
1007
|
root[key].format === RGBAFormat && root[key].type === UnsignedByteType) {
|
|
990
1008
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
@@ -1018,38 +1036,60 @@ function applyProps(object, props) {
|
|
|
1018
1036
|
return object;
|
|
1019
1037
|
}
|
|
1020
1038
|
|
|
1039
|
+
const DEFAULT_POINTER_ID = 0;
|
|
1040
|
+
const XR_POINTER_ID_START = 1e3;
|
|
1041
|
+
function getPointerState(internal, pointerId) {
|
|
1042
|
+
let state = internal.pointerMap.get(pointerId);
|
|
1043
|
+
if (!state) {
|
|
1044
|
+
state = {
|
|
1045
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
1046
|
+
captured: /* @__PURE__ */ new Map(),
|
|
1047
|
+
initialClick: [0, 0],
|
|
1048
|
+
initialHits: []
|
|
1049
|
+
};
|
|
1050
|
+
internal.pointerMap.set(pointerId, state);
|
|
1051
|
+
}
|
|
1052
|
+
return state;
|
|
1053
|
+
}
|
|
1054
|
+
function getPointerId(event) {
|
|
1055
|
+
return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
|
|
1056
|
+
}
|
|
1021
1057
|
function makeId(event) {
|
|
1022
1058
|
return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
|
|
1023
1059
|
}
|
|
1024
|
-
function releaseInternalPointerCapture(
|
|
1025
|
-
const
|
|
1060
|
+
function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
1061
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1062
|
+
if (!pointerState) return;
|
|
1063
|
+
const captureData = pointerState.captured.get(obj);
|
|
1026
1064
|
if (captureData) {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
capturedMap.delete(pointerId);
|
|
1030
|
-
captureData.target.releasePointerCapture(pointerId);
|
|
1031
|
-
}
|
|
1065
|
+
pointerState.captured.delete(obj);
|
|
1066
|
+
captureData.target.releasePointerCapture(pointerId);
|
|
1032
1067
|
}
|
|
1033
1068
|
}
|
|
1034
1069
|
function removeInteractivity(store, object) {
|
|
1035
1070
|
const { internal } = store.getState();
|
|
1036
1071
|
internal.interaction = internal.interaction.filter((o) => o !== object);
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1072
|
+
for (const [pointerId, pointerState] of internal.pointerMap) {
|
|
1073
|
+
pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
|
|
1074
|
+
pointerState.hovered.forEach((value, key) => {
|
|
1075
|
+
if (value.eventObject === object || value.object === object) {
|
|
1076
|
+
pointerState.hovered.delete(key);
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
if (pointerState.captured.has(object)) {
|
|
1080
|
+
releaseInternalPointerCapture(internal, object, pointerId);
|
|
1041
1081
|
}
|
|
1042
|
-
}
|
|
1043
|
-
internal.capturedMap.forEach((captures, pointerId) => {
|
|
1044
|
-
releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
|
|
1045
|
-
});
|
|
1082
|
+
}
|
|
1046
1083
|
unregisterVisibility(store, object);
|
|
1047
1084
|
}
|
|
1048
1085
|
function createEvents(store) {
|
|
1049
|
-
function calculateDistance(event) {
|
|
1086
|
+
function calculateDistance(event, pointerId) {
|
|
1050
1087
|
const { internal } = store.getState();
|
|
1051
|
-
const
|
|
1052
|
-
|
|
1088
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1089
|
+
if (!pointerState) return 0;
|
|
1090
|
+
const [initialX, initialY] = pointerState.initialClick;
|
|
1091
|
+
const dx = event.offsetX - initialX;
|
|
1092
|
+
const dy = event.offsetY - initialY;
|
|
1053
1093
|
return Math.round(Math.sqrt(dx * dx + dy * dy));
|
|
1054
1094
|
}
|
|
1055
1095
|
function filterPointerEvents(objects) {
|
|
@@ -1085,6 +1125,15 @@ function createEvents(store) {
|
|
|
1085
1125
|
return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
|
|
1086
1126
|
}
|
|
1087
1127
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
1128
|
+
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
1129
|
+
const bInteractivePriority = b.object.userData?.interactivePriority;
|
|
1130
|
+
if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
|
|
1131
|
+
if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
|
|
1132
|
+
if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
|
|
1133
|
+
if (aInteractivePriority !== bInteractivePriority) {
|
|
1134
|
+
return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1088
1137
|
const aState = getRootState(a.object);
|
|
1089
1138
|
const bState = getRootState(b.object);
|
|
1090
1139
|
const aPriority = aState?.events?.priority ?? 1;
|
|
@@ -1106,9 +1155,13 @@ function createEvents(store) {
|
|
|
1106
1155
|
eventObject = eventObject.parent;
|
|
1107
1156
|
}
|
|
1108
1157
|
}
|
|
1109
|
-
if ("pointerId" in event
|
|
1110
|
-
|
|
1111
|
-
|
|
1158
|
+
if ("pointerId" in event) {
|
|
1159
|
+
const pointerId = event.pointerId;
|
|
1160
|
+
const pointerState = state.internal.pointerMap.get(pointerId);
|
|
1161
|
+
if (pointerState?.captured.size) {
|
|
1162
|
+
for (const captureData of pointerState.captured.values()) {
|
|
1163
|
+
if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
|
|
1164
|
+
}
|
|
1112
1165
|
}
|
|
1113
1166
|
}
|
|
1114
1167
|
return intersections;
|
|
@@ -1121,27 +1174,25 @@ function createEvents(store) {
|
|
|
1121
1174
|
if (state) {
|
|
1122
1175
|
const { raycaster, pointer, camera, internal } = state;
|
|
1123
1176
|
const unprojectedPoint = new Vector3(pointer.x, pointer.y, 0).unproject(camera);
|
|
1124
|
-
const hasPointerCapture = (id) =>
|
|
1177
|
+
const hasPointerCapture = (id) => {
|
|
1178
|
+
const pointerState = internal.pointerMap.get(id);
|
|
1179
|
+
return pointerState?.captured.has(hit.eventObject) ?? false;
|
|
1180
|
+
};
|
|
1125
1181
|
const setPointerCapture = (id) => {
|
|
1126
1182
|
const captureData = { intersection: hit, target: event.target };
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
} else {
|
|
1130
|
-
internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
|
|
1131
|
-
}
|
|
1183
|
+
const pointerState = getPointerState(internal, id);
|
|
1184
|
+
pointerState.captured.set(hit.eventObject, captureData);
|
|
1132
1185
|
event.target.setPointerCapture(id);
|
|
1133
1186
|
};
|
|
1134
1187
|
const releasePointerCapture = (id) => {
|
|
1135
|
-
|
|
1136
|
-
if (captures) {
|
|
1137
|
-
releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
|
|
1138
|
-
}
|
|
1188
|
+
releaseInternalPointerCapture(internal, hit.eventObject, id);
|
|
1139
1189
|
};
|
|
1140
1190
|
const extractEventProps = {};
|
|
1141
1191
|
for (const prop in event) {
|
|
1142
1192
|
const property = event[prop];
|
|
1143
1193
|
if (typeof property !== "function") extractEventProps[prop] = property;
|
|
1144
1194
|
}
|
|
1195
|
+
const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
|
|
1145
1196
|
const raycastEvent = {
|
|
1146
1197
|
...hit,
|
|
1147
1198
|
...extractEventProps,
|
|
@@ -1152,18 +1203,19 @@ function createEvents(store) {
|
|
|
1152
1203
|
unprojectedPoint,
|
|
1153
1204
|
ray: raycaster.ray,
|
|
1154
1205
|
camera,
|
|
1206
|
+
pointerId: eventPointerId,
|
|
1155
1207
|
// Hijack stopPropagation, which just sets a flag
|
|
1156
1208
|
stopPropagation() {
|
|
1157
|
-
const
|
|
1209
|
+
const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
|
|
1158
1210
|
if (
|
|
1159
1211
|
// ...if this pointer hasn't been captured
|
|
1160
|
-
!
|
|
1161
|
-
|
|
1212
|
+
!pointerState?.captured.size || // ... or if the hit object is capturing the pointer
|
|
1213
|
+
pointerState.captured.has(hit.eventObject)
|
|
1162
1214
|
) {
|
|
1163
1215
|
raycastEvent.stopped = localState.stopped = true;
|
|
1164
|
-
if (
|
|
1216
|
+
if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
|
|
1165
1217
|
const higher = intersections.slice(0, intersections.indexOf(hit));
|
|
1166
|
-
cancelPointer([...higher, hit]);
|
|
1218
|
+
cancelPointer([...higher, hit], eventPointerId);
|
|
1167
1219
|
}
|
|
1168
1220
|
}
|
|
1169
1221
|
},
|
|
@@ -1179,15 +1231,18 @@ function createEvents(store) {
|
|
|
1179
1231
|
}
|
|
1180
1232
|
return intersections;
|
|
1181
1233
|
}
|
|
1182
|
-
function cancelPointer(intersections) {
|
|
1234
|
+
function cancelPointer(intersections, pointerId) {
|
|
1183
1235
|
const { internal } = store.getState();
|
|
1184
|
-
|
|
1236
|
+
const pid = pointerId ?? DEFAULT_POINTER_ID;
|
|
1237
|
+
const pointerState = internal.pointerMap.get(pid);
|
|
1238
|
+
if (!pointerState) return;
|
|
1239
|
+
for (const [hoveredId, hoveredObj] of pointerState.hovered) {
|
|
1185
1240
|
if (!intersections.length || !intersections.find(
|
|
1186
1241
|
(hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
|
|
1187
1242
|
)) {
|
|
1188
1243
|
const eventObject = hoveredObj.eventObject;
|
|
1189
1244
|
const instance = eventObject.__r3f;
|
|
1190
|
-
|
|
1245
|
+
pointerState.hovered.delete(hoveredId);
|
|
1191
1246
|
if (instance?.eventCount) {
|
|
1192
1247
|
const handlers = instance.handlers;
|
|
1193
1248
|
const data = { ...hoveredObj, intersections };
|
|
@@ -1216,41 +1271,118 @@ function createEvents(store) {
|
|
|
1216
1271
|
instance?.handlers.onDropMissed?.(event);
|
|
1217
1272
|
}
|
|
1218
1273
|
}
|
|
1274
|
+
function cleanupPointer(pointerId) {
|
|
1275
|
+
const { internal } = store.getState();
|
|
1276
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1277
|
+
if (pointerState) {
|
|
1278
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1279
|
+
const eventObject = hoveredObj.eventObject;
|
|
1280
|
+
const instance = eventObject.__r3f;
|
|
1281
|
+
if (instance?.eventCount) {
|
|
1282
|
+
const handlers = instance.handlers;
|
|
1283
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1284
|
+
handlers.onPointerOut?.(data);
|
|
1285
|
+
handlers.onPointerLeave?.(data);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
internal.pointerMap.delete(pointerId);
|
|
1289
|
+
}
|
|
1290
|
+
internal.pointerDirty.delete(pointerId);
|
|
1291
|
+
}
|
|
1292
|
+
function processDeferredPointer(event, pointerId) {
|
|
1293
|
+
const state = store.getState();
|
|
1294
|
+
const { internal } = state;
|
|
1295
|
+
if (!state.events.enabled) return;
|
|
1296
|
+
const filter = filterPointerEvents;
|
|
1297
|
+
const hits = intersect(event, filter);
|
|
1298
|
+
cancelPointer(hits, pointerId);
|
|
1299
|
+
function onIntersect(data) {
|
|
1300
|
+
const eventObject = data.eventObject;
|
|
1301
|
+
const instance = eventObject.__r3f;
|
|
1302
|
+
if (!instance?.eventCount) return;
|
|
1303
|
+
const handlers = instance.handlers;
|
|
1304
|
+
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1305
|
+
const id = makeId(data);
|
|
1306
|
+
const pointerState = getPointerState(internal, pointerId);
|
|
1307
|
+
const hoveredItem = pointerState.hovered.get(id);
|
|
1308
|
+
if (!hoveredItem) {
|
|
1309
|
+
pointerState.hovered.set(id, data);
|
|
1310
|
+
handlers.onPointerOver?.(data);
|
|
1311
|
+
handlers.onPointerEnter?.(data);
|
|
1312
|
+
} else if (hoveredItem.stopped) {
|
|
1313
|
+
data.stopPropagation();
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
handlers.onPointerMove?.(data);
|
|
1317
|
+
}
|
|
1318
|
+
handleIntersects(hits, event, 0, onIntersect);
|
|
1319
|
+
}
|
|
1219
1320
|
function handlePointer(name) {
|
|
1220
1321
|
switch (name) {
|
|
1221
1322
|
case "onPointerLeave":
|
|
1222
|
-
case "onPointerCancel":
|
|
1223
1323
|
case "onDragLeave":
|
|
1224
1324
|
return () => cancelPointer([]);
|
|
1325
|
+
// Global cancel of these events
|
|
1326
|
+
case "onPointerCancel":
|
|
1327
|
+
return (event) => {
|
|
1328
|
+
const pointerId = getPointerId(event);
|
|
1329
|
+
cleanupPointer(pointerId);
|
|
1330
|
+
};
|
|
1225
1331
|
case "onLostPointerCapture":
|
|
1226
1332
|
return (event) => {
|
|
1227
1333
|
const { internal } = store.getState();
|
|
1228
|
-
|
|
1334
|
+
const pointerId = getPointerId(event);
|
|
1335
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1336
|
+
if (pointerState?.captured.size) {
|
|
1229
1337
|
requestAnimationFrame(() => {
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1338
|
+
const pointerState2 = internal.pointerMap.get(pointerId);
|
|
1339
|
+
if (pointerState2?.captured.size) {
|
|
1340
|
+
pointerState2.captured.clear();
|
|
1233
1341
|
}
|
|
1342
|
+
cancelPointer([], pointerId);
|
|
1234
1343
|
});
|
|
1235
1344
|
}
|
|
1236
1345
|
};
|
|
1237
1346
|
}
|
|
1238
1347
|
return function handleEvent(event) {
|
|
1239
1348
|
const state = store.getState();
|
|
1240
|
-
const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
|
|
1349
|
+
const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
|
|
1350
|
+
const pointerId = getPointerId(event);
|
|
1241
1351
|
internal.lastEvent.current = event;
|
|
1242
|
-
if (!
|
|
1352
|
+
if (!events.enabled) return;
|
|
1243
1353
|
const isPointerMove = name === "onPointerMove";
|
|
1244
1354
|
const isDragOver = name === "onDragOver";
|
|
1245
1355
|
const isDrop = name === "onDrop";
|
|
1246
1356
|
const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
|
|
1357
|
+
const isPointerDown = name === "onPointerDown";
|
|
1358
|
+
const isPointerUp = name === "onPointerUp";
|
|
1359
|
+
const isWheel = name === "onWheel";
|
|
1360
|
+
const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
|
|
1361
|
+
if (isPointerMove && canDeferRaycasts) {
|
|
1362
|
+
events.compute?.(event, state);
|
|
1363
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
|
|
1367
|
+
events.compute?.(event, state);
|
|
1368
|
+
internal.pointerDirty.set(pointerId, event);
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
|
|
1372
|
+
const deferredEvent = internal.pointerDirty.get(pointerId);
|
|
1373
|
+
internal.pointerDirty.delete(pointerId);
|
|
1374
|
+
processDeferredPointer(deferredEvent, pointerId);
|
|
1375
|
+
}
|
|
1247
1376
|
const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
|
|
1248
1377
|
const hits = intersect(event, filter);
|
|
1249
|
-
const delta = isClickEvent ? calculateDistance(event) : 0;
|
|
1250
|
-
if (
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1378
|
+
const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
|
|
1379
|
+
if (isPointerDown) {
|
|
1380
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1381
|
+
pointerState2.initialClick = [event.offsetX, event.offsetY];
|
|
1382
|
+
pointerState2.initialHits = hits.map((hit) => hit.eventObject);
|
|
1383
|
+
}
|
|
1384
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1385
|
+
const initialHits = pointerState?.initialHits ?? [];
|
|
1254
1386
|
if (isClickEvent && !hits.length) {
|
|
1255
1387
|
if (delta <= 2) {
|
|
1256
1388
|
pointerMissed(event, internal.interaction);
|
|
@@ -1265,7 +1397,9 @@ function createEvents(store) {
|
|
|
1265
1397
|
dropMissed(event, internal.interaction);
|
|
1266
1398
|
if (onDropMissed) onDropMissed(event);
|
|
1267
1399
|
}
|
|
1268
|
-
if (isPointerMove || isDragOver)
|
|
1400
|
+
if (isPointerMove || isDragOver) {
|
|
1401
|
+
cancelPointer(hits, pointerId);
|
|
1402
|
+
}
|
|
1269
1403
|
function onIntersect(data) {
|
|
1270
1404
|
const eventObject = data.eventObject;
|
|
1271
1405
|
const instance = eventObject.__r3f;
|
|
@@ -1274,9 +1408,10 @@ function createEvents(store) {
|
|
|
1274
1408
|
if (isPointerMove) {
|
|
1275
1409
|
if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
|
|
1276
1410
|
const id = makeId(data);
|
|
1277
|
-
const
|
|
1411
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1412
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1278
1413
|
if (!hoveredItem) {
|
|
1279
|
-
|
|
1414
|
+
pointerState2.hovered.set(id, data);
|
|
1280
1415
|
handlers.onPointerOver?.(data);
|
|
1281
1416
|
handlers.onPointerEnter?.(data);
|
|
1282
1417
|
} else if (hoveredItem.stopped) {
|
|
@@ -1286,9 +1421,10 @@ function createEvents(store) {
|
|
|
1286
1421
|
handlers.onPointerMove?.(data);
|
|
1287
1422
|
} else if (isDragOver) {
|
|
1288
1423
|
const id = makeId(data);
|
|
1289
|
-
const
|
|
1424
|
+
const pointerState2 = getPointerState(internal, pointerId);
|
|
1425
|
+
const hoveredItem = pointerState2.hovered.get(id);
|
|
1290
1426
|
if (!hoveredItem) {
|
|
1291
|
-
|
|
1427
|
+
pointerState2.hovered.set(id, data);
|
|
1292
1428
|
handlers.onDragOverEnter?.(data);
|
|
1293
1429
|
} else if (hoveredItem.stopped) {
|
|
1294
1430
|
data.stopPropagation();
|
|
@@ -1299,18 +1435,18 @@ function createEvents(store) {
|
|
|
1299
1435
|
} else {
|
|
1300
1436
|
const handler = handlers[name];
|
|
1301
1437
|
if (handler) {
|
|
1302
|
-
if (!isClickEvent ||
|
|
1438
|
+
if (!isClickEvent || initialHits.includes(eventObject)) {
|
|
1303
1439
|
pointerMissed(
|
|
1304
1440
|
event,
|
|
1305
|
-
internal.interaction.filter((object) => !
|
|
1441
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1306
1442
|
);
|
|
1307
1443
|
handler(data);
|
|
1308
1444
|
}
|
|
1309
1445
|
} else {
|
|
1310
|
-
if (isClickEvent &&
|
|
1446
|
+
if (isClickEvent && initialHits.includes(eventObject)) {
|
|
1311
1447
|
pointerMissed(
|
|
1312
1448
|
event,
|
|
1313
|
-
internal.interaction.filter((object) => !
|
|
1449
|
+
internal.interaction.filter((object) => !initialHits.includes(object))
|
|
1314
1450
|
);
|
|
1315
1451
|
}
|
|
1316
1452
|
}
|
|
@@ -1319,7 +1455,15 @@ function createEvents(store) {
|
|
|
1319
1455
|
handleIntersects(hits, event, delta, onIntersect);
|
|
1320
1456
|
};
|
|
1321
1457
|
}
|
|
1322
|
-
|
|
1458
|
+
function flushDeferredPointers() {
|
|
1459
|
+
const { internal, events } = store.getState();
|
|
1460
|
+
if (!events.frameTimedRaycasts) return;
|
|
1461
|
+
for (const [pointerId, event] of internal.pointerDirty) {
|
|
1462
|
+
processDeferredPointer(event, pointerId);
|
|
1463
|
+
}
|
|
1464
|
+
internal.pointerDirty.clear();
|
|
1465
|
+
}
|
|
1466
|
+
return { handlePointer, flushDeferredPointers, processDeferredPointer };
|
|
1323
1467
|
}
|
|
1324
1468
|
const DOM_EVENTS = {
|
|
1325
1469
|
onClick: ["click", false],
|
|
@@ -1338,10 +1482,15 @@ const DOM_EVENTS = {
|
|
|
1338
1482
|
onLostPointerCapture: ["lostpointercapture", true]
|
|
1339
1483
|
};
|
|
1340
1484
|
function createPointerEvents(store) {
|
|
1341
|
-
const { handlePointer } = createEvents(store);
|
|
1485
|
+
const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
|
|
1486
|
+
let nextXRPointerId = XR_POINTER_ID_START;
|
|
1487
|
+
const xrPointers = /* @__PURE__ */ new Map();
|
|
1342
1488
|
return {
|
|
1343
1489
|
priority: 1,
|
|
1344
1490
|
enabled: true,
|
|
1491
|
+
frameTimedRaycasts: true,
|
|
1492
|
+
alwaysFireOnScroll: true,
|
|
1493
|
+
updateOnFrame: false,
|
|
1345
1494
|
compute(event, state) {
|
|
1346
1495
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
1347
1496
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
@@ -1351,11 +1500,33 @@ function createPointerEvents(store) {
|
|
|
1351
1500
|
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
1352
1501
|
{}
|
|
1353
1502
|
),
|
|
1354
|
-
update: () => {
|
|
1503
|
+
update: (pointerId) => {
|
|
1355
1504
|
const { events, internal } = store.getState();
|
|
1356
|
-
if (
|
|
1505
|
+
if (!events.handlers) return;
|
|
1506
|
+
if (pointerId !== void 0) {
|
|
1507
|
+
const event = internal.pointerDirty.get(pointerId);
|
|
1508
|
+
if (event) {
|
|
1509
|
+
internal.pointerDirty.delete(pointerId);
|
|
1510
|
+
processDeferredPointer(event, pointerId);
|
|
1511
|
+
} else if (internal.lastEvent?.current) {
|
|
1512
|
+
processDeferredPointer(internal.lastEvent.current, pointerId);
|
|
1513
|
+
}
|
|
1514
|
+
} else {
|
|
1515
|
+
flushDeferredPointers();
|
|
1516
|
+
if (internal.lastEvent?.current) {
|
|
1517
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
},
|
|
1521
|
+
flush: () => {
|
|
1522
|
+
const { events, internal } = store.getState();
|
|
1523
|
+
flushDeferredPointers();
|
|
1524
|
+
if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
|
|
1525
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
1526
|
+
}
|
|
1357
1527
|
},
|
|
1358
1528
|
connect: (target) => {
|
|
1529
|
+
if (!target) return;
|
|
1359
1530
|
const { set, events } = store.getState();
|
|
1360
1531
|
events.disconnect?.();
|
|
1361
1532
|
set((state) => ({ events: { ...state.events, connected: target } }));
|
|
@@ -1379,6 +1550,32 @@ function createPointerEvents(store) {
|
|
|
1379
1550
|
}
|
|
1380
1551
|
set((state) => ({ events: { ...state.events, connected: void 0 } }));
|
|
1381
1552
|
}
|
|
1553
|
+
},
|
|
1554
|
+
registerPointer: (config) => {
|
|
1555
|
+
const pointerId = nextXRPointerId++;
|
|
1556
|
+
xrPointers.set(pointerId, config);
|
|
1557
|
+
const { internal } = store.getState();
|
|
1558
|
+
getPointerState(internal, pointerId);
|
|
1559
|
+
return pointerId;
|
|
1560
|
+
},
|
|
1561
|
+
unregisterPointer: (pointerId) => {
|
|
1562
|
+
xrPointers.delete(pointerId);
|
|
1563
|
+
const { internal } = store.getState();
|
|
1564
|
+
const pointerState = internal.pointerMap.get(pointerId);
|
|
1565
|
+
if (pointerState) {
|
|
1566
|
+
for (const [, hoveredObj] of pointerState.hovered) {
|
|
1567
|
+
const eventObject = hoveredObj.eventObject;
|
|
1568
|
+
const instance = eventObject.__r3f;
|
|
1569
|
+
if (instance?.eventCount) {
|
|
1570
|
+
const handlers = instance.handlers;
|
|
1571
|
+
const data = { ...hoveredObj, intersections: [] };
|
|
1572
|
+
handlers.onPointerOut?.(data);
|
|
1573
|
+
handlers.onPointerLeave?.(data);
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
internal.pointerMap.delete(pointerId);
|
|
1577
|
+
}
|
|
1578
|
+
internal.pointerDirty.delete(pointerId);
|
|
1382
1579
|
}
|
|
1383
1580
|
};
|
|
1384
1581
|
}
|
|
@@ -1692,7 +1889,7 @@ function shouldRun(job, now) {
|
|
|
1692
1889
|
const minInterval = 1e3 / job.fps;
|
|
1693
1890
|
const lastRun = job.lastRun ?? 0;
|
|
1694
1891
|
const elapsed = now - lastRun;
|
|
1695
|
-
if (elapsed < minInterval) return false;
|
|
1892
|
+
if (elapsed < minInterval - 1) return false;
|
|
1696
1893
|
if (job.drop) {
|
|
1697
1894
|
job.lastRun = now;
|
|
1698
1895
|
} else {
|
|
@@ -2509,7 +2706,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2509
2706
|
frustum: new Frustum(),
|
|
2510
2707
|
autoUpdateFrustum: true,
|
|
2511
2708
|
raycaster: null,
|
|
2512
|
-
events: {
|
|
2709
|
+
events: {
|
|
2710
|
+
priority: 1,
|
|
2711
|
+
enabled: true,
|
|
2712
|
+
connected: false,
|
|
2713
|
+
frameTimedRaycasts: true,
|
|
2714
|
+
alwaysFireOnScroll: true,
|
|
2715
|
+
updateOnFrame: false
|
|
2716
|
+
},
|
|
2513
2717
|
scene: null,
|
|
2514
2718
|
rootScene: null,
|
|
2515
2719
|
xr: null,
|
|
@@ -2600,11 +2804,14 @@ const createStore = (invalidate, advance) => {
|
|
|
2600
2804
|
},
|
|
2601
2805
|
setError: (error) => set(() => ({ error })),
|
|
2602
2806
|
error: null,
|
|
2603
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures,
|
|
2807
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
2604
2808
|
uniforms: {},
|
|
2605
2809
|
nodes: {},
|
|
2810
|
+
buffers: {},
|
|
2811
|
+
gpuStorage: {},
|
|
2606
2812
|
textures: /* @__PURE__ */ new Map(),
|
|
2607
|
-
|
|
2813
|
+
_textureRefs: /* @__PURE__ */ new Map(),
|
|
2814
|
+
renderPipeline: null,
|
|
2608
2815
|
passes: {},
|
|
2609
2816
|
_hmrVersion: 0,
|
|
2610
2817
|
_sizeImperative: false,
|
|
@@ -2613,12 +2820,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2613
2820
|
internal: {
|
|
2614
2821
|
// Events
|
|
2615
2822
|
interaction: [],
|
|
2616
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
2617
2823
|
subscribers: [],
|
|
2824
|
+
// Per-pointer state (new unified structure)
|
|
2825
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
2826
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
2827
|
+
lastEvent: React.createRef(),
|
|
2828
|
+
// Deprecated but kept for backwards compatibility
|
|
2829
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2618
2830
|
initialClick: [0, 0],
|
|
2619
2831
|
initialHits: [],
|
|
2620
2832
|
capturedMap: /* @__PURE__ */ new Map(),
|
|
2621
|
-
lastEvent: React.createRef(),
|
|
2622
2833
|
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2623
2834
|
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2624
2835
|
// Occlusion system (WebGPU only)
|
|
@@ -2706,14 +2917,16 @@ const createStore = (invalidate, advance) => {
|
|
|
2706
2917
|
oldSize = size;
|
|
2707
2918
|
oldDpr = viewport.dpr;
|
|
2708
2919
|
updateCamera(camera, size);
|
|
2709
|
-
if (canvasTarget) {
|
|
2920
|
+
if (internal.isSecondary && canvasTarget) {
|
|
2710
2921
|
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2711
|
-
|
|
2712
|
-
canvasTarget.setSize(size.width, size.height, updateStyle);
|
|
2922
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2713
2923
|
} else {
|
|
2714
2924
|
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
2715
|
-
|
|
2716
|
-
|
|
2925
|
+
actualRenderer.setSize(size.width, size.height, false);
|
|
2926
|
+
if (canvasTarget) {
|
|
2927
|
+
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2928
|
+
canvasTarget.setSize(size.width, size.height, false);
|
|
2929
|
+
}
|
|
2717
2930
|
}
|
|
2718
2931
|
}
|
|
2719
2932
|
if (camera !== oldCamera) {
|
|
@@ -2961,18 +3174,18 @@ function buildFromCache(input, textureCache) {
|
|
|
2961
3174
|
function useTexture(input, optionsOrOnLoad) {
|
|
2962
3175
|
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
2963
3176
|
const store = useStore();
|
|
2964
|
-
const textureCache = useThree((state) => state.textures);
|
|
2965
3177
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
2966
|
-
const { onLoad, cache =
|
|
3178
|
+
const { onLoad, cache = true } = options;
|
|
2967
3179
|
const onLoadRef = useRef(onLoad);
|
|
2968
3180
|
onLoadRef.current = onLoad;
|
|
2969
3181
|
const onLoadCalledForRef = useRef(null);
|
|
2970
3182
|
const urls = useMemo(() => getUrls(input), [input]);
|
|
2971
3183
|
const cachedResult = useMemo(() => {
|
|
2972
3184
|
if (!cache) return null;
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
3185
|
+
const textures = store.getState().textures;
|
|
3186
|
+
if (!allUrlsCached(urls, textures)) return null;
|
|
3187
|
+
return buildFromCache(input, textures);
|
|
3188
|
+
}, [cache, urls, input, store]);
|
|
2976
3189
|
const loadedTextures = useLoader(
|
|
2977
3190
|
TextureLoader,
|
|
2978
3191
|
IsObject(input) ? Object.values(input) : input
|
|
@@ -3016,8 +3229,6 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3016
3229
|
}, [input, loadedTextures, cachedResult]);
|
|
3017
3230
|
useEffect(() => {
|
|
3018
3231
|
if (!cache) return;
|
|
3019
|
-
if (cachedResult) return;
|
|
3020
|
-
const set = store.setState;
|
|
3021
3232
|
const urlTextureMap = [];
|
|
3022
3233
|
if (typeof input === "string") {
|
|
3023
3234
|
urlTextureMap.push([input, mappedTextures]);
|
|
@@ -3031,18 +3242,32 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
3031
3242
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
3032
3243
|
}
|
|
3033
3244
|
}
|
|
3034
|
-
|
|
3035
|
-
const
|
|
3036
|
-
let
|
|
3245
|
+
store.setState((state) => {
|
|
3246
|
+
const refs = new Map(state._textureRefs);
|
|
3247
|
+
let textures = state.textures;
|
|
3248
|
+
let added = false;
|
|
3037
3249
|
for (const [url, texture] of urlTextureMap) {
|
|
3038
|
-
if (!
|
|
3039
|
-
|
|
3040
|
-
|
|
3250
|
+
if (!textures.has(url)) {
|
|
3251
|
+
if (!added) {
|
|
3252
|
+
textures = new Map(textures);
|
|
3253
|
+
added = true;
|
|
3254
|
+
}
|
|
3255
|
+
textures.set(url, texture);
|
|
3041
3256
|
}
|
|
3257
|
+
refs.set(url, (refs.get(url) ?? 0) + 1);
|
|
3042
3258
|
}
|
|
3043
|
-
return
|
|
3259
|
+
return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
|
|
3260
|
+
});
|
|
3261
|
+
return () => store.setState((state) => {
|
|
3262
|
+
const refs = new Map(state._textureRefs);
|
|
3263
|
+
for (const [url] of urlTextureMap) {
|
|
3264
|
+
const next = (refs.get(url) ?? 0) - 1;
|
|
3265
|
+
if (next <= 0) refs.delete(url);
|
|
3266
|
+
else refs.set(url, next);
|
|
3267
|
+
}
|
|
3268
|
+
return { _textureRefs: refs };
|
|
3044
3269
|
});
|
|
3045
|
-
}, [cache, input, mappedTextures, store
|
|
3270
|
+
}, [cache, input, mappedTextures, store]);
|
|
3046
3271
|
return mappedTextures;
|
|
3047
3272
|
}
|
|
3048
3273
|
useTexture.preload = (url) => useLoader.preload(TextureLoader, url);
|
|
@@ -3058,96 +3283,63 @@ const Texture = ({
|
|
|
3058
3283
|
return /* @__PURE__ */ jsx(Fragment, { children: children?.(ret) });
|
|
3059
3284
|
};
|
|
3060
3285
|
|
|
3061
|
-
function
|
|
3062
|
-
if (entry instanceof Texture$1) return entry;
|
|
3063
|
-
if (entry && typeof entry === "object" && "value" in entry && entry.value instanceof Texture$1) {
|
|
3064
|
-
return entry.value;
|
|
3065
|
-
}
|
|
3066
|
-
return null;
|
|
3067
|
-
}
|
|
3068
|
-
function useTextures() {
|
|
3286
|
+
function useTextures(selector) {
|
|
3069
3287
|
const store = useStore();
|
|
3070
|
-
|
|
3071
|
-
const set = store.setState;
|
|
3288
|
+
const registry = useMemo(() => {
|
|
3072
3289
|
const getState = store.getState;
|
|
3073
|
-
const
|
|
3074
|
-
|
|
3075
|
-
const newMap = new Map(state.textures);
|
|
3076
|
-
newMap.set(key, value);
|
|
3077
|
-
return { textures: newMap };
|
|
3078
|
-
});
|
|
3079
|
-
};
|
|
3080
|
-
const addMultiple = (items) => {
|
|
3081
|
-
set((state) => {
|
|
3082
|
-
const newMap = new Map(state.textures);
|
|
3083
|
-
const entries = items instanceof Map ? items.entries() : Object.entries(items);
|
|
3084
|
-
for (const [key, value] of entries) {
|
|
3085
|
-
newMap.set(key, value);
|
|
3086
|
-
}
|
|
3087
|
-
return { textures: newMap };
|
|
3088
|
-
});
|
|
3089
|
-
};
|
|
3090
|
-
const remove = (key) => {
|
|
3091
|
-
set((state) => {
|
|
3092
|
-
const newMap = new Map(state.textures);
|
|
3093
|
-
newMap.delete(key);
|
|
3094
|
-
return { textures: newMap };
|
|
3095
|
-
});
|
|
3096
|
-
};
|
|
3097
|
-
const removeMultiple = (keys) => {
|
|
3098
|
-
set((state) => {
|
|
3099
|
-
const newMap = new Map(state.textures);
|
|
3100
|
-
for (const key of keys) newMap.delete(key);
|
|
3101
|
-
return { textures: newMap };
|
|
3102
|
-
});
|
|
3103
|
-
};
|
|
3104
|
-
const dispose = (key) => {
|
|
3105
|
-
const entry = getState().textures.get(key);
|
|
3106
|
-
if (entry) {
|
|
3107
|
-
const tex = getTextureValue(entry);
|
|
3108
|
-
tex?.dispose();
|
|
3109
|
-
}
|
|
3110
|
-
remove(key);
|
|
3111
|
-
};
|
|
3112
|
-
const disposeMultiple = (keys) => {
|
|
3113
|
-
const textures = getState().textures;
|
|
3114
|
-
for (const key of keys) {
|
|
3115
|
-
const entry = textures.get(key);
|
|
3116
|
-
if (entry) {
|
|
3117
|
-
const tex = getTextureValue(entry);
|
|
3118
|
-
tex?.dispose();
|
|
3119
|
-
}
|
|
3120
|
-
}
|
|
3121
|
-
removeMultiple(keys);
|
|
3122
|
-
};
|
|
3123
|
-
const disposeAll = () => {
|
|
3124
|
-
const textures = getState().textures;
|
|
3125
|
-
for (const entry of textures.values()) {
|
|
3126
|
-
const tex = getTextureValue(entry);
|
|
3127
|
-
tex?.dispose();
|
|
3128
|
-
}
|
|
3129
|
-
set({ textures: /* @__PURE__ */ new Map() });
|
|
3130
|
-
};
|
|
3290
|
+
const setState = store.setState;
|
|
3291
|
+
const getOne = (key) => getState().textures.get(key);
|
|
3131
3292
|
return {
|
|
3132
|
-
|
|
3133
|
-
get textures() {
|
|
3293
|
+
get all() {
|
|
3134
3294
|
return getState().textures;
|
|
3135
3295
|
},
|
|
3136
|
-
|
|
3137
|
-
|
|
3296
|
+
get(input) {
|
|
3297
|
+
if (typeof input === "string") return getOne(input);
|
|
3298
|
+
if (Array.isArray(input)) return input.map(getOne);
|
|
3299
|
+
const out = {};
|
|
3300
|
+
for (const name in input) out[name] = getOne(input[name]);
|
|
3301
|
+
return out;
|
|
3302
|
+
},
|
|
3138
3303
|
has: (key) => getState().textures.has(key),
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3304
|
+
add(keyOrRecord, texture) {
|
|
3305
|
+
setState((state) => {
|
|
3306
|
+
const textures = new Map(state.textures);
|
|
3307
|
+
if (typeof keyOrRecord === "string") {
|
|
3308
|
+
textures.set(keyOrRecord, texture);
|
|
3309
|
+
} else {
|
|
3310
|
+
for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
|
|
3311
|
+
}
|
|
3312
|
+
return { textures };
|
|
3313
|
+
});
|
|
3314
|
+
},
|
|
3315
|
+
dispose(key, options) {
|
|
3316
|
+
const state = getState();
|
|
3317
|
+
const refs = state._textureRefs.get(key) ?? 0;
|
|
3318
|
+
if (refs > 0 && !options?.force) {
|
|
3319
|
+
console.warn(
|
|
3320
|
+
`[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
|
|
3321
|
+
);
|
|
3322
|
+
return false;
|
|
3323
|
+
}
|
|
3324
|
+
state.textures.get(key)?.dispose();
|
|
3325
|
+
setState((s) => {
|
|
3326
|
+
const textures = new Map(s.textures);
|
|
3327
|
+
textures.delete(key);
|
|
3328
|
+
const nextRefs = new Map(s._textureRefs);
|
|
3329
|
+
nextRefs.delete(key);
|
|
3330
|
+
return { textures, _textureRefs: nextRefs };
|
|
3331
|
+
});
|
|
3332
|
+
return true;
|
|
3333
|
+
},
|
|
3334
|
+
disposeAll() {
|
|
3335
|
+
for (const texture of getState().textures.values()) texture.dispose();
|
|
3336
|
+
setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
|
|
3337
|
+
}
|
|
3149
3338
|
};
|
|
3150
3339
|
}, [store]);
|
|
3340
|
+
const subscribe = selector ? () => selector(registry) : (state) => state.textures;
|
|
3341
|
+
const selected = useThree(subscribe);
|
|
3342
|
+
return selector ? selected : registry;
|
|
3151
3343
|
}
|
|
3152
3344
|
|
|
3153
3345
|
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
@@ -14998,7 +15190,6 @@ function createRoot(canvas) {
|
|
|
14998
15190
|
events,
|
|
14999
15191
|
onCreated: onCreatedCallback,
|
|
15000
15192
|
shadows = false,
|
|
15001
|
-
textureColorSpace = SRGBColorSpace,
|
|
15002
15193
|
orthographic = false,
|
|
15003
15194
|
frameloop = "always",
|
|
15004
15195
|
dpr = [1, 2],
|
|
@@ -15013,6 +15204,7 @@ function createRoot(canvas) {
|
|
|
15013
15204
|
_sizeProps,
|
|
15014
15205
|
forceEven
|
|
15015
15206
|
} = props;
|
|
15207
|
+
const textureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || SRGBColorSpace;
|
|
15016
15208
|
const state = store.getState();
|
|
15017
15209
|
const defaultGPUProps = {
|
|
15018
15210
|
canvas,
|
|
@@ -15050,6 +15242,12 @@ function createRoot(canvas) {
|
|
|
15050
15242
|
} else if (!state.internal.actualRenderer) {
|
|
15051
15243
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, WebGPURenderer);
|
|
15052
15244
|
if (!renderer.hasInitialized?.()) {
|
|
15245
|
+
const size2 = computeInitialSize(canvas, propsSize);
|
|
15246
|
+
if (size2.width > 0 && size2.height > 0) {
|
|
15247
|
+
const pixelRatio = calculateDpr(dpr);
|
|
15248
|
+
canvas.width = size2.width * pixelRatio;
|
|
15249
|
+
canvas.height = size2.height * pixelRatio;
|
|
15250
|
+
}
|
|
15053
15251
|
await renderer.init();
|
|
15054
15252
|
}
|
|
15055
15253
|
const backend = renderer.backend;
|
|
@@ -15159,7 +15357,7 @@ function createRoot(canvas) {
|
|
|
15159
15357
|
lastConfiguredProps.performance = performance;
|
|
15160
15358
|
}
|
|
15161
15359
|
if (!state.xr) {
|
|
15162
|
-
const handleXRFrame = (timestamp,
|
|
15360
|
+
const handleXRFrame = (timestamp, _frame) => {
|
|
15163
15361
|
const state2 = store.getState();
|
|
15164
15362
|
if (state2.frameloop === "never") return;
|
|
15165
15363
|
advance(timestamp);
|
|
@@ -15195,15 +15393,22 @@ function createRoot(canvas) {
|
|
|
15195
15393
|
const oldType = renderer.shadowMap.type;
|
|
15196
15394
|
renderer.shadowMap.enabled = !!shadows;
|
|
15197
15395
|
if (is.boo(shadows)) {
|
|
15198
|
-
renderer.shadowMap.type =
|
|
15396
|
+
renderer.shadowMap.type = PCFShadowMap;
|
|
15199
15397
|
} else if (is.str(shadows)) {
|
|
15398
|
+
if (shadows === "soft") {
|
|
15399
|
+
notifyDepreciated({
|
|
15400
|
+
heading: 'shadows="soft" is deprecated',
|
|
15401
|
+
body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
|
|
15402
|
+
link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
|
|
15403
|
+
});
|
|
15404
|
+
}
|
|
15200
15405
|
const types = {
|
|
15201
15406
|
basic: BasicShadowMap,
|
|
15202
15407
|
percentage: PCFShadowMap,
|
|
15203
|
-
soft:
|
|
15408
|
+
soft: PCFShadowMap,
|
|
15204
15409
|
variance: VSMShadowMap
|
|
15205
15410
|
};
|
|
15206
|
-
renderer.shadowMap.type = types[shadows] ??
|
|
15411
|
+
renderer.shadowMap.type = types[shadows] ?? PCFShadowMap;
|
|
15207
15412
|
} else if (is.obj(shadows)) {
|
|
15208
15413
|
Object.assign(renderer.shadowMap, shadows);
|
|
15209
15414
|
}
|
|
@@ -15219,13 +15424,24 @@ function createRoot(canvas) {
|
|
|
15219
15424
|
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
15220
15425
|
lastConfiguredProps.textureColorSpace = textureColorSpace;
|
|
15221
15426
|
}
|
|
15427
|
+
const r3fProps = ["textureColorSpace"];
|
|
15428
|
+
const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
|
|
15429
|
+
const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
|
|
15222
15430
|
if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
|
|
15223
|
-
|
|
15431
|
+
const glProps = {};
|
|
15432
|
+
for (const key in glConfig) {
|
|
15433
|
+
if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
|
|
15434
|
+
}
|
|
15435
|
+
applyProps(renderer, glProps);
|
|
15224
15436
|
}
|
|
15225
15437
|
if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
|
|
15226
15438
|
const currentRenderer = state.renderer;
|
|
15227
15439
|
if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
|
|
15228
|
-
|
|
15440
|
+
const rendererProps = {};
|
|
15441
|
+
for (const key in rendererConfig) {
|
|
15442
|
+
if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
|
|
15443
|
+
}
|
|
15444
|
+
applyProps(currentRenderer, rendererProps);
|
|
15229
15445
|
}
|
|
15230
15446
|
}
|
|
15231
15447
|
const scheduler = getScheduler();
|
|
@@ -15251,6 +15467,18 @@ function createRoot(canvas) {
|
|
|
15251
15467
|
system: true
|
|
15252
15468
|
}
|
|
15253
15469
|
);
|
|
15470
|
+
const unregisterEventsFlush = scheduler.register(
|
|
15471
|
+
() => {
|
|
15472
|
+
const state2 = store.getState();
|
|
15473
|
+
state2.events.flush?.();
|
|
15474
|
+
},
|
|
15475
|
+
{
|
|
15476
|
+
id: `${newRootId}_events`,
|
|
15477
|
+
rootId: newRootId,
|
|
15478
|
+
phase: "input",
|
|
15479
|
+
system: true
|
|
15480
|
+
}
|
|
15481
|
+
);
|
|
15254
15482
|
const unregisterFrustum = scheduler.register(
|
|
15255
15483
|
() => {
|
|
15256
15484
|
const state2 = store.getState();
|
|
@@ -15285,7 +15513,7 @@ function createRoot(canvas) {
|
|
|
15285
15513
|
const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
|
|
15286
15514
|
if (userHandlesRender || state2.internal.priority) return;
|
|
15287
15515
|
try {
|
|
15288
|
-
if (state2.
|
|
15516
|
+
if (state2.renderPipeline?.render) state2.renderPipeline.render();
|
|
15289
15517
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
15290
15518
|
} catch (error) {
|
|
15291
15519
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -15310,6 +15538,7 @@ function createRoot(canvas) {
|
|
|
15310
15538
|
unregisterRoot: () => {
|
|
15311
15539
|
unregisterRoot();
|
|
15312
15540
|
unregisterCanvasTarget();
|
|
15541
|
+
unregisterEventsFlush();
|
|
15313
15542
|
unregisterFrustum();
|
|
15314
15543
|
unregisterVisibility();
|
|
15315
15544
|
unregisterRender();
|
|
@@ -15475,9 +15704,13 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
15475
15704
|
const store = createWithEqualityFn((set, get) => ({ ...rest, set, get }));
|
|
15476
15705
|
const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
|
|
15477
15706
|
onMutate(previousRoot.getState());
|
|
15478
|
-
previousRoot.subscribe(onMutate);
|
|
15479
15707
|
return store;
|
|
15480
15708
|
}, [previousRoot, container]);
|
|
15709
|
+
useIsomorphicLayoutEffect(() => {
|
|
15710
|
+
const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
|
|
15711
|
+
const unsubscribe = previousRoot.subscribe(onMutate);
|
|
15712
|
+
return unsubscribe;
|
|
15713
|
+
}, [previousRoot, usePortalStore]);
|
|
15481
15714
|
return (
|
|
15482
15715
|
// @ts-ignore, reconciler types are not maintained
|
|
15483
15716
|
/* @__PURE__ */ jsx(Fragment, { children: reconciler.createPortal(
|
|
@@ -15522,8 +15755,18 @@ function CanvasImpl({
|
|
|
15522
15755
|
forceEven,
|
|
15523
15756
|
...props
|
|
15524
15757
|
}) {
|
|
15525
|
-
const
|
|
15526
|
-
|
|
15758
|
+
const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
|
|
15759
|
+
let primaryCanvas;
|
|
15760
|
+
let scheduler;
|
|
15761
|
+
let renderer;
|
|
15762
|
+
if (isRendererConfig) {
|
|
15763
|
+
const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
|
|
15764
|
+
primaryCanvas = pc;
|
|
15765
|
+
scheduler = sc;
|
|
15766
|
+
renderer = Object.keys(rest).length > 0 ? rest : rendererProp;
|
|
15767
|
+
} else {
|
|
15768
|
+
renderer = rendererProp;
|
|
15769
|
+
}
|
|
15527
15770
|
React.useMemo(() => extend(THREE), []);
|
|
15528
15771
|
const Bridge = useBridge();
|
|
15529
15772
|
const backgroundProps = React.useMemo(() => {
|
|
@@ -15698,6 +15941,7 @@ function CanvasImpl({
|
|
|
15698
15941
|
queueMicrotask(() => {
|
|
15699
15942
|
const rootEntry = _roots.get(canvas);
|
|
15700
15943
|
if (rootEntry?.store) {
|
|
15944
|
+
console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
|
|
15701
15945
|
rootEntry.store.setState((state) => ({
|
|
15702
15946
|
nodes: {},
|
|
15703
15947
|
uniforms: {},
|
|
@@ -15709,8 +15953,7 @@ function CanvasImpl({
|
|
|
15709
15953
|
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
15710
15954
|
const hot = import.meta.hot;
|
|
15711
15955
|
hot.on("vite:afterUpdate", handleHMR);
|
|
15712
|
-
return () => hot.
|
|
15713
|
-
});
|
|
15956
|
+
return () => hot.off?.("vite:afterUpdate", handleHMR);
|
|
15714
15957
|
}
|
|
15715
15958
|
if (typeof module !== "undefined" && module.hot) {
|
|
15716
15959
|
const hot = module.hot;
|
|
@@ -15733,7 +15976,16 @@ function CanvasImpl({
|
|
|
15733
15976
|
...style
|
|
15734
15977
|
},
|
|
15735
15978
|
...props,
|
|
15736
|
-
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
|
|
15979
|
+
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
|
|
15980
|
+
"canvas",
|
|
15981
|
+
{
|
|
15982
|
+
ref: canvasRef,
|
|
15983
|
+
id,
|
|
15984
|
+
className: "r3f-canvas",
|
|
15985
|
+
style: { display: "block", width: "100%", height: "100%" },
|
|
15986
|
+
children: fallback
|
|
15987
|
+
}
|
|
15988
|
+
) })
|
|
15737
15989
|
}
|
|
15738
15990
|
);
|
|
15739
15991
|
}
|
|
@@ -15809,6 +16061,8 @@ function createScopedStore(data) {
|
|
|
15809
16061
|
function createLazyCreatorState(state) {
|
|
15810
16062
|
let _uniforms = null;
|
|
15811
16063
|
let _nodes = null;
|
|
16064
|
+
let _buffers = null;
|
|
16065
|
+
let _gpuStorage = null;
|
|
15812
16066
|
return Object.create(state, {
|
|
15813
16067
|
uniforms: {
|
|
15814
16068
|
get() {
|
|
@@ -15819,6 +16073,16 @@ function createLazyCreatorState(state) {
|
|
|
15819
16073
|
get() {
|
|
15820
16074
|
return _nodes ?? (_nodes = createScopedStore(state.nodes));
|
|
15821
16075
|
}
|
|
16076
|
+
},
|
|
16077
|
+
buffers: {
|
|
16078
|
+
get() {
|
|
16079
|
+
return _buffers ?? (_buffers = createScopedStore(state.buffers));
|
|
16080
|
+
}
|
|
16081
|
+
},
|
|
16082
|
+
gpuStorage: {
|
|
16083
|
+
get() {
|
|
16084
|
+
return _gpuStorage ?? (_gpuStorage = createScopedStore(state.gpuStorage));
|
|
16085
|
+
}
|
|
15822
16086
|
}
|
|
15823
16087
|
});
|
|
15824
16088
|
}
|
|
@@ -15901,6 +16165,10 @@ function vectorize(inObject) {
|
|
|
15901
16165
|
if (obj.isVector2 || obj.isVector3 || obj.isVector4) return inObject;
|
|
15902
16166
|
if (obj.isMatrix3 || obj.isMatrix4) return inObject;
|
|
15903
16167
|
if (obj.isColor || obj.isEuler || obj.isQuaternion || obj.isSpherical) return inObject;
|
|
16168
|
+
if ("r" in obj && "g" in obj && "b" in obj && typeof obj.r === "number" && typeof obj.g === "number" && typeof obj.b === "number") {
|
|
16169
|
+
const scale = obj.r > 1 || obj.g > 1 || obj.b > 1 ? 1 / 255 : 1;
|
|
16170
|
+
return new Color(obj.r * scale, obj.g * scale, obj.b * scale);
|
|
16171
|
+
}
|
|
15904
16172
|
if ("x" in obj && "y" in obj && typeof obj.x === "number" && typeof obj.y === "number") {
|
|
15905
16173
|
if ("w" in obj && typeof obj.w === "number" && "z" in obj && typeof obj.z === "number") {
|
|
15906
16174
|
return new Vector4(obj.x, obj.y, obj.z, obj.w);
|
|
@@ -16356,7 +16624,351 @@ function useLocalNodes(creator) {
|
|
|
16356
16624
|
}, [store, creator, uniforms, nodes, textures, hmrVersion]);
|
|
16357
16625
|
}
|
|
16358
16626
|
|
|
16359
|
-
|
|
16627
|
+
const isBufferLike = (value) => {
|
|
16628
|
+
if (value === null || typeof value !== "object") return false;
|
|
16629
|
+
if (ArrayBuffer.isView(value)) return true;
|
|
16630
|
+
if ("isBufferAttribute" in value) return true;
|
|
16631
|
+
if ("uuid" in value || "nodeType" in value) return true;
|
|
16632
|
+
return false;
|
|
16633
|
+
};
|
|
16634
|
+
const disposeBuffer = (buffer) => {
|
|
16635
|
+
if (buffer === null || typeof buffer !== "object") return;
|
|
16636
|
+
if ("dispose" in buffer && typeof buffer.dispose === "function") {
|
|
16637
|
+
buffer.dispose();
|
|
16638
|
+
}
|
|
16639
|
+
};
|
|
16640
|
+
function useBuffers(creatorOrScope, scope) {
|
|
16641
|
+
const store = useStore();
|
|
16642
|
+
const removeBuffers = useCallback(
|
|
16643
|
+
(names, targetScope) => {
|
|
16644
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16645
|
+
store.setState((state) => {
|
|
16646
|
+
if (targetScope) {
|
|
16647
|
+
const currentScope = { ...state.buffers[targetScope] };
|
|
16648
|
+
for (const name of nameArray) delete currentScope[name];
|
|
16649
|
+
return { buffers: { ...state.buffers, [targetScope]: currentScope } };
|
|
16650
|
+
}
|
|
16651
|
+
const buffers2 = { ...state.buffers };
|
|
16652
|
+
for (const name of nameArray) if (isBufferLike(buffers2[name])) delete buffers2[name];
|
|
16653
|
+
return { buffers: buffers2 };
|
|
16654
|
+
});
|
|
16655
|
+
},
|
|
16656
|
+
[store]
|
|
16657
|
+
);
|
|
16658
|
+
const clearBuffers = useCallback(
|
|
16659
|
+
(targetScope) => {
|
|
16660
|
+
store.setState((state) => {
|
|
16661
|
+
if (targetScope && targetScope !== "root") {
|
|
16662
|
+
const { [targetScope]: _, ...rest } = state.buffers;
|
|
16663
|
+
return { buffers: rest };
|
|
16664
|
+
}
|
|
16665
|
+
if (targetScope === "root") {
|
|
16666
|
+
const buffers2 = {};
|
|
16667
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16668
|
+
if (!isBufferLike(value)) buffers2[key] = value;
|
|
16669
|
+
}
|
|
16670
|
+
return { buffers: buffers2 };
|
|
16671
|
+
}
|
|
16672
|
+
return { buffers: {} };
|
|
16673
|
+
});
|
|
16674
|
+
},
|
|
16675
|
+
[store]
|
|
16676
|
+
);
|
|
16677
|
+
const rebuildBuffers = useCallback(
|
|
16678
|
+
(targetScope) => {
|
|
16679
|
+
store.setState((state) => {
|
|
16680
|
+
let newBuffers = state.buffers;
|
|
16681
|
+
if (targetScope && targetScope !== "root") {
|
|
16682
|
+
const { [targetScope]: _, ...rest } = state.buffers;
|
|
16683
|
+
newBuffers = rest;
|
|
16684
|
+
} else if (targetScope === "root") {
|
|
16685
|
+
newBuffers = {};
|
|
16686
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16687
|
+
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
16688
|
+
}
|
|
16689
|
+
} else {
|
|
16690
|
+
newBuffers = {};
|
|
16691
|
+
}
|
|
16692
|
+
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
16693
|
+
});
|
|
16694
|
+
},
|
|
16695
|
+
[store]
|
|
16696
|
+
);
|
|
16697
|
+
const disposeBuffers = useCallback(
|
|
16698
|
+
(names, targetScope) => {
|
|
16699
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16700
|
+
const state = store.getState();
|
|
16701
|
+
for (const name of nameArray) {
|
|
16702
|
+
const buffer = targetScope ? state.buffers[targetScope]?.[name] : state.buffers[name];
|
|
16703
|
+
if (buffer && isBufferLike(buffer)) {
|
|
16704
|
+
disposeBuffer(buffer);
|
|
16705
|
+
}
|
|
16706
|
+
}
|
|
16707
|
+
removeBuffers(names, targetScope);
|
|
16708
|
+
},
|
|
16709
|
+
[store, removeBuffers]
|
|
16710
|
+
);
|
|
16711
|
+
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
16712
|
+
const storeBuffers = useThree((s) => s.buffers);
|
|
16713
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16714
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16715
|
+
const readerDep = isReader ? storeBuffers : null;
|
|
16716
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
16717
|
+
const buffers = useMemo(() => {
|
|
16718
|
+
if (creatorOrScope === void 0) {
|
|
16719
|
+
return storeBuffers;
|
|
16720
|
+
}
|
|
16721
|
+
if (typeof creatorOrScope === "string") {
|
|
16722
|
+
const scopeData = storeBuffers[creatorOrScope];
|
|
16723
|
+
if (scopeData && !isBufferLike(scopeData)) return scopeData;
|
|
16724
|
+
return {};
|
|
16725
|
+
}
|
|
16726
|
+
const state = store.getState();
|
|
16727
|
+
const set = store.setState;
|
|
16728
|
+
const creator = creatorOrScope;
|
|
16729
|
+
const wrappedState = createLazyCreatorState(state);
|
|
16730
|
+
const created = creator(wrappedState);
|
|
16731
|
+
const result = {};
|
|
16732
|
+
let hasNewBuffers = false;
|
|
16733
|
+
if (scope) {
|
|
16734
|
+
const currentScope = state.buffers[scope] ?? {};
|
|
16735
|
+
for (const [name, buffer] of Object.entries(created)) {
|
|
16736
|
+
if (currentScope[name]) {
|
|
16737
|
+
result[name] = currentScope[name];
|
|
16738
|
+
} else {
|
|
16739
|
+
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
16740
|
+
buffer.setName(`${scope}.${name}`);
|
|
16741
|
+
}
|
|
16742
|
+
result[name] = buffer;
|
|
16743
|
+
hasNewBuffers = true;
|
|
16744
|
+
}
|
|
16745
|
+
}
|
|
16746
|
+
if (hasNewBuffers) {
|
|
16747
|
+
set((s) => ({
|
|
16748
|
+
buffers: {
|
|
16749
|
+
...s.buffers,
|
|
16750
|
+
[scope]: { ...s.buffers[scope], ...result }
|
|
16751
|
+
}
|
|
16752
|
+
}));
|
|
16753
|
+
}
|
|
16754
|
+
return result;
|
|
16755
|
+
}
|
|
16756
|
+
for (const [name, buffer] of Object.entries(created)) {
|
|
16757
|
+
const existing = state.buffers[name];
|
|
16758
|
+
if (existing && isBufferLike(existing)) {
|
|
16759
|
+
result[name] = existing;
|
|
16760
|
+
} else {
|
|
16761
|
+
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
16762
|
+
buffer.setName(name);
|
|
16763
|
+
}
|
|
16764
|
+
result[name] = buffer;
|
|
16765
|
+
hasNewBuffers = true;
|
|
16766
|
+
}
|
|
16767
|
+
}
|
|
16768
|
+
if (hasNewBuffers) {
|
|
16769
|
+
set((s) => ({ buffers: { ...s.buffers, ...result } }));
|
|
16770
|
+
}
|
|
16771
|
+
return result;
|
|
16772
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
16773
|
+
return { ...buffers, removeBuffers, clearBuffers, rebuildBuffers, disposeBuffers };
|
|
16774
|
+
}
|
|
16775
|
+
function rebuildAllBuffers(store, scope) {
|
|
16776
|
+
store.setState((state) => {
|
|
16777
|
+
let newBuffers = state.buffers;
|
|
16778
|
+
if (scope && scope !== "root") {
|
|
16779
|
+
const { [scope]: _, ...rest } = state.buffers;
|
|
16780
|
+
newBuffers = rest;
|
|
16781
|
+
} else if (scope === "root") {
|
|
16782
|
+
newBuffers = {};
|
|
16783
|
+
for (const [key, value] of Object.entries(state.buffers)) {
|
|
16784
|
+
if (!isBufferLike(value)) newBuffers[key] = value;
|
|
16785
|
+
}
|
|
16786
|
+
} else {
|
|
16787
|
+
newBuffers = {};
|
|
16788
|
+
}
|
|
16789
|
+
return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
|
|
16790
|
+
});
|
|
16791
|
+
}
|
|
16792
|
+
|
|
16793
|
+
const isStorageLike = (value) => {
|
|
16794
|
+
if (value === null || typeof value !== "object") return false;
|
|
16795
|
+
if ("isTexture" in value) return true;
|
|
16796
|
+
if ("isData3DTexture" in value) return true;
|
|
16797
|
+
if ("uuid" in value || "nodeType" in value) return true;
|
|
16798
|
+
return false;
|
|
16799
|
+
};
|
|
16800
|
+
const disposeStorage = (storage) => {
|
|
16801
|
+
if (storage === null || typeof storage !== "object") return;
|
|
16802
|
+
if ("dispose" in storage && typeof storage.dispose === "function") {
|
|
16803
|
+
storage.dispose();
|
|
16804
|
+
}
|
|
16805
|
+
};
|
|
16806
|
+
function useGPUStorage(creatorOrScope, scope) {
|
|
16807
|
+
const store = useStore();
|
|
16808
|
+
const removeStorage = useCallback(
|
|
16809
|
+
(names, targetScope) => {
|
|
16810
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16811
|
+
store.setState((state) => {
|
|
16812
|
+
if (targetScope) {
|
|
16813
|
+
const currentScope = { ...state.gpuStorage[targetScope] };
|
|
16814
|
+
for (const name of nameArray) delete currentScope[name];
|
|
16815
|
+
return { gpuStorage: { ...state.gpuStorage, [targetScope]: currentScope } };
|
|
16816
|
+
}
|
|
16817
|
+
const gpuStorage2 = { ...state.gpuStorage };
|
|
16818
|
+
for (const name of nameArray) if (isStorageLike(gpuStorage2[name])) delete gpuStorage2[name];
|
|
16819
|
+
return { gpuStorage: gpuStorage2 };
|
|
16820
|
+
});
|
|
16821
|
+
},
|
|
16822
|
+
[store]
|
|
16823
|
+
);
|
|
16824
|
+
const clearStorage = useCallback(
|
|
16825
|
+
(targetScope) => {
|
|
16826
|
+
store.setState((state) => {
|
|
16827
|
+
if (targetScope && targetScope !== "root") {
|
|
16828
|
+
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
16829
|
+
return { gpuStorage: rest };
|
|
16830
|
+
}
|
|
16831
|
+
if (targetScope === "root") {
|
|
16832
|
+
const gpuStorage2 = {};
|
|
16833
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16834
|
+
if (!isStorageLike(value)) gpuStorage2[key] = value;
|
|
16835
|
+
}
|
|
16836
|
+
return { gpuStorage: gpuStorage2 };
|
|
16837
|
+
}
|
|
16838
|
+
return { gpuStorage: {} };
|
|
16839
|
+
});
|
|
16840
|
+
},
|
|
16841
|
+
[store]
|
|
16842
|
+
);
|
|
16843
|
+
const rebuildStorage = useCallback(
|
|
16844
|
+
(targetScope) => {
|
|
16845
|
+
store.setState((state) => {
|
|
16846
|
+
let newStorage = state.gpuStorage;
|
|
16847
|
+
if (targetScope && targetScope !== "root") {
|
|
16848
|
+
const { [targetScope]: _, ...rest } = state.gpuStorage;
|
|
16849
|
+
newStorage = rest;
|
|
16850
|
+
} else if (targetScope === "root") {
|
|
16851
|
+
newStorage = {};
|
|
16852
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16853
|
+
if (!isStorageLike(value)) newStorage[key] = value;
|
|
16854
|
+
}
|
|
16855
|
+
} else {
|
|
16856
|
+
newStorage = {};
|
|
16857
|
+
}
|
|
16858
|
+
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
16859
|
+
});
|
|
16860
|
+
},
|
|
16861
|
+
[store]
|
|
16862
|
+
);
|
|
16863
|
+
const disposeStorageFn = useCallback(
|
|
16864
|
+
(names, targetScope) => {
|
|
16865
|
+
const nameArray = Array.isArray(names) ? names : [names];
|
|
16866
|
+
const state = store.getState();
|
|
16867
|
+
for (const name of nameArray) {
|
|
16868
|
+
const storage = targetScope ? state.gpuStorage[targetScope]?.[name] : state.gpuStorage[name];
|
|
16869
|
+
if (storage && isStorageLike(storage)) {
|
|
16870
|
+
disposeStorage(storage);
|
|
16871
|
+
}
|
|
16872
|
+
}
|
|
16873
|
+
removeStorage(names, targetScope);
|
|
16874
|
+
},
|
|
16875
|
+
[store, removeStorage]
|
|
16876
|
+
);
|
|
16877
|
+
const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
|
|
16878
|
+
const storeStorage = useThree((s) => s.gpuStorage);
|
|
16879
|
+
const hmrVersion = useThree((s) => s._hmrVersion);
|
|
16880
|
+
const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
|
|
16881
|
+
const readerDep = isReader ? storeStorage : null;
|
|
16882
|
+
const creatorDep = isReader ? null : hmrVersion;
|
|
16883
|
+
const gpuStorage = useMemo(() => {
|
|
16884
|
+
if (creatorOrScope === void 0) {
|
|
16885
|
+
return storeStorage;
|
|
16886
|
+
}
|
|
16887
|
+
if (typeof creatorOrScope === "string") {
|
|
16888
|
+
const scopeData = storeStorage[creatorOrScope];
|
|
16889
|
+
if (scopeData && !isStorageLike(scopeData)) return scopeData;
|
|
16890
|
+
return {};
|
|
16891
|
+
}
|
|
16892
|
+
const state = store.getState();
|
|
16893
|
+
const set = store.setState;
|
|
16894
|
+
const creator = creatorOrScope;
|
|
16895
|
+
const wrappedState = createLazyCreatorState(state);
|
|
16896
|
+
const created = creator(wrappedState);
|
|
16897
|
+
const result = {};
|
|
16898
|
+
let hasNewStorage = false;
|
|
16899
|
+
if (scope) {
|
|
16900
|
+
const currentScope = state.gpuStorage[scope] ?? {};
|
|
16901
|
+
for (const [name, storage] of Object.entries(created)) {
|
|
16902
|
+
if (currentScope[name]) {
|
|
16903
|
+
result[name] = currentScope[name];
|
|
16904
|
+
} else {
|
|
16905
|
+
if ("setName" in storage && typeof storage.setName === "function") {
|
|
16906
|
+
storage.setName(`${scope}.${name}`);
|
|
16907
|
+
}
|
|
16908
|
+
if ("name" in storage && typeof storage.name === "string") {
|
|
16909
|
+
storage.name = `${scope}.${name}`;
|
|
16910
|
+
}
|
|
16911
|
+
result[name] = storage;
|
|
16912
|
+
hasNewStorage = true;
|
|
16913
|
+
}
|
|
16914
|
+
}
|
|
16915
|
+
if (hasNewStorage) {
|
|
16916
|
+
set((s) => ({
|
|
16917
|
+
gpuStorage: {
|
|
16918
|
+
...s.gpuStorage,
|
|
16919
|
+
[scope]: { ...s.gpuStorage[scope], ...result }
|
|
16920
|
+
}
|
|
16921
|
+
}));
|
|
16922
|
+
}
|
|
16923
|
+
return result;
|
|
16924
|
+
}
|
|
16925
|
+
for (const [name, storage] of Object.entries(created)) {
|
|
16926
|
+
const existing = state.gpuStorage[name];
|
|
16927
|
+
if (existing && isStorageLike(existing)) {
|
|
16928
|
+
result[name] = existing;
|
|
16929
|
+
} else {
|
|
16930
|
+
if ("setName" in storage && typeof storage.setName === "function") {
|
|
16931
|
+
storage.setName(name);
|
|
16932
|
+
}
|
|
16933
|
+
if ("name" in storage && typeof storage.name === "string") {
|
|
16934
|
+
storage.name = name;
|
|
16935
|
+
}
|
|
16936
|
+
result[name] = storage;
|
|
16937
|
+
hasNewStorage = true;
|
|
16938
|
+
}
|
|
16939
|
+
}
|
|
16940
|
+
if (hasNewStorage) {
|
|
16941
|
+
set((s) => ({ gpuStorage: { ...s.gpuStorage, ...result } }));
|
|
16942
|
+
}
|
|
16943
|
+
return result;
|
|
16944
|
+
}, [store, scopeDep, readerDep, creatorDep]);
|
|
16945
|
+
return {
|
|
16946
|
+
...gpuStorage,
|
|
16947
|
+
removeStorage,
|
|
16948
|
+
clearStorage,
|
|
16949
|
+
rebuildStorage,
|
|
16950
|
+
disposeStorage: disposeStorageFn
|
|
16951
|
+
};
|
|
16952
|
+
}
|
|
16953
|
+
function rebuildAllStorage(store, scope) {
|
|
16954
|
+
store.setState((state) => {
|
|
16955
|
+
let newStorage = state.gpuStorage;
|
|
16956
|
+
if (scope && scope !== "root") {
|
|
16957
|
+
const { [scope]: _, ...rest } = state.gpuStorage;
|
|
16958
|
+
newStorage = rest;
|
|
16959
|
+
} else if (scope === "root") {
|
|
16960
|
+
newStorage = {};
|
|
16961
|
+
for (const [key, value] of Object.entries(state.gpuStorage)) {
|
|
16962
|
+
if (!isStorageLike(value)) newStorage[key] = value;
|
|
16963
|
+
}
|
|
16964
|
+
} else {
|
|
16965
|
+
newStorage = {};
|
|
16966
|
+
}
|
|
16967
|
+
return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
|
|
16968
|
+
});
|
|
16969
|
+
}
|
|
16970
|
+
|
|
16971
|
+
function useRenderPipeline(mainCB, setupCB) {
|
|
16360
16972
|
const store = useStore();
|
|
16361
16973
|
const { scene, camera, renderer, isLegacy } = useThree();
|
|
16362
16974
|
const callbacksRanRef = useRef(false);
|
|
@@ -16375,7 +16987,7 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16375
16987
|
}, [store]);
|
|
16376
16988
|
const reset = useCallback(() => {
|
|
16377
16989
|
store.setState({
|
|
16378
|
-
|
|
16990
|
+
renderPipeline: null,
|
|
16379
16991
|
passes: {}
|
|
16380
16992
|
});
|
|
16381
16993
|
callbacksRanRef.current = false;
|
|
@@ -16388,13 +17000,13 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16388
17000
|
}, []);
|
|
16389
17001
|
useLayoutEffect(() => {
|
|
16390
17002
|
if (isLegacy) {
|
|
16391
|
-
throw new Error("
|
|
17003
|
+
throw new Error("useRenderPipeline is only available with WebGPU renderer. Set renderer prop on Canvas.");
|
|
16392
17004
|
}
|
|
16393
17005
|
if (!renderer || !scene || !camera) return;
|
|
16394
17006
|
const state = store.getState();
|
|
16395
17007
|
const set = store.setState;
|
|
16396
17008
|
try {
|
|
16397
|
-
let pp = state.
|
|
17009
|
+
let pp = state.renderPipeline;
|
|
16398
17010
|
let currentPasses = { ...state.passes };
|
|
16399
17011
|
let justCreatedPP = false;
|
|
16400
17012
|
if (!pp) {
|
|
@@ -16411,7 +17023,7 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16411
17023
|
}
|
|
16412
17024
|
currentPasses.scenePass = scenePass;
|
|
16413
17025
|
if (!pp.outputNode || justCreatedPP) pp.outputNode = scenePass;
|
|
16414
|
-
set({
|
|
17026
|
+
set({ renderPipeline: pp, passes: currentPasses });
|
|
16415
17027
|
const shouldRunCallbacks = justCreatedPP || !callbacksRanRef.current || !cacheValid;
|
|
16416
17028
|
if (shouldRunCallbacks) {
|
|
16417
17029
|
if (setupCBRef.current) {
|
|
@@ -16433,22 +17045,22 @@ function usePostProcessing(mainCB, setupCB) {
|
|
|
16433
17045
|
callbacksRanRef.current = true;
|
|
16434
17046
|
}
|
|
16435
17047
|
} catch (error) {
|
|
16436
|
-
console.error("[
|
|
17048
|
+
console.error("[useRenderPipeline] Setup error:", error);
|
|
16437
17049
|
}
|
|
16438
17050
|
}, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
|
|
16439
17051
|
const passes = useThree((s) => s.passes);
|
|
16440
|
-
const
|
|
17052
|
+
const renderPipeline = useThree((s) => s.renderPipeline);
|
|
16441
17053
|
return {
|
|
16442
17054
|
passes,
|
|
16443
|
-
|
|
17055
|
+
renderPipeline,
|
|
16444
17056
|
clearPasses,
|
|
16445
17057
|
reset,
|
|
16446
17058
|
rebuild,
|
|
16447
|
-
// isReady indicates if
|
|
16448
|
-
isReady:
|
|
17059
|
+
// isReady indicates if RenderPipeline is configured and ready for rendering
|
|
17060
|
+
isReady: renderPipeline !== null
|
|
16449
17061
|
};
|
|
16450
17062
|
}
|
|
16451
17063
|
|
|
16452
17064
|
extend(THREE);
|
|
16453
17065
|
|
|
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,
|
|
17066
|
+
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, rebuildAllBuffers, rebuildAllNodes, rebuildAllStorage, rebuildAllUniforms, reconciler, registerPrimary, removeInteractivity, removeNodes, removeUniforms, resolve, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useBuffers, useEnvironment, useFrame, useGPUStorage, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useLocalNodes, useMutableCallback, useNodes, useRenderPipeline, useRenderTarget, useStore, useTexture, useTextures, useThree, useUniform, useUniforms, waitForPrimary };
|