@react-three/tsl 10.0.0-canary.87166dc → 10.0.0-canary.88b1ca7
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 +221 -95
- package/dist/index.d.cts +307 -66
- package/dist/index.d.mts +307 -66
- package/dist/index.d.ts +307 -66
- package/dist/index.mjs +222 -96
- package/package.json +2 -2
- package/readme.md +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { registerRootExtension, getTextureView, useStore, useThree
|
|
1
|
+
import { setRenderOverride, registerRootExtension, getTextureView, useStore, useThree } from '@react-three/fiber/extension';
|
|
2
2
|
import { uniform, pass } from 'three/tsl';
|
|
3
3
|
import * as THREE from 'three/webgpu';
|
|
4
4
|
import { Color } from 'three/webgpu';
|
|
@@ -58,6 +58,13 @@ function withStagedOverlay(store, kind, committed) {
|
|
|
58
58
|
}
|
|
59
59
|
return view;
|
|
60
60
|
}
|
|
61
|
+
function readWithStaged(store, kind, committed, scope, isLeaf) {
|
|
62
|
+
if (scope === void 0) return withStagedOverlay(store, kind, committed);
|
|
63
|
+
const scopeData = committed[scope];
|
|
64
|
+
const current = scopeData && typeof scopeData === "object" && !isLeaf(scopeData) ? scopeData : {};
|
|
65
|
+
const staged = scope === ROOT_SCOPE ? void 0 : peekStaged(store, kind, scope);
|
|
66
|
+
return staged ? { ...current, ...staged } : current;
|
|
67
|
+
}
|
|
61
68
|
function flushStagedScope(store, kind, scopeKey, isLeaf) {
|
|
62
69
|
const registry = getKindRegistry(store, kind);
|
|
63
70
|
const staged = registry.staged.get(scopeKey);
|
|
@@ -256,6 +263,103 @@ function configureTSL(next) {
|
|
|
256
263
|
for (const store of primaries) applyConfig(store, config);
|
|
257
264
|
}
|
|
258
265
|
|
|
266
|
+
const owners = /* @__PURE__ */ new WeakMap();
|
|
267
|
+
const warned$1 = /* @__PURE__ */ new WeakSet();
|
|
268
|
+
const sweeps = /* @__PURE__ */ new WeakMap();
|
|
269
|
+
function createOwner(store, rebuild) {
|
|
270
|
+
return { store, pipeline: null, scenePass: null, passes: {}, mounted: false, releaseTimer: null, rebuild };
|
|
271
|
+
}
|
|
272
|
+
function disposeOwnerResources(owner) {
|
|
273
|
+
owner.scenePass?.node.dispose();
|
|
274
|
+
owner.pipeline?.dispose();
|
|
275
|
+
owner.scenePass = null;
|
|
276
|
+
owner.pipeline = null;
|
|
277
|
+
owner.passes = {};
|
|
278
|
+
}
|
|
279
|
+
function activeOwner(store) {
|
|
280
|
+
return owners.get(store)?.at(-1);
|
|
281
|
+
}
|
|
282
|
+
function renderThroughPipeline(store) {
|
|
283
|
+
return () => {
|
|
284
|
+
const pipeline = store.getState().renderPipeline;
|
|
285
|
+
if (pipeline?.render) pipeline.render();
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function claimOwnership(owner) {
|
|
289
|
+
if (owner.releaseTimer !== null) clearTimeout(owner.releaseTimer);
|
|
290
|
+
owner.releaseTimer = null;
|
|
291
|
+
owner.mounted = true;
|
|
292
|
+
let list = owners.get(owner.store);
|
|
293
|
+
if (!list) owners.set(owner.store, list = []);
|
|
294
|
+
if (list.includes(owner)) return;
|
|
295
|
+
if (list.some((other) => other.mounted) && !warned$1.has(owner.store)) {
|
|
296
|
+
warned$1.add(owner.store);
|
|
297
|
+
if (typeof process === "undefined" || process.env.NODE_ENV !== "production") {
|
|
298
|
+
console.warn(
|
|
299
|
+
"[useRenderPipeline] More than one mounted component configures this canvas's render pipeline. The most recently mounted one renders; the others take over again when it unmounts."
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
list.push(owner);
|
|
304
|
+
scheduleSweep(owner.store);
|
|
305
|
+
}
|
|
306
|
+
function scheduleSweep(store) {
|
|
307
|
+
if (sweeps.has(store)) return;
|
|
308
|
+
sweeps.set(
|
|
309
|
+
store,
|
|
310
|
+
setTimeout(() => {
|
|
311
|
+
sweeps.delete(store);
|
|
312
|
+
const active = activeOwner(store);
|
|
313
|
+
for (const owner of [...owners.get(store) ?? []]) {
|
|
314
|
+
if (owner !== active && !owner.mounted && owner.releaseTimer === null) releaseOwner(owner);
|
|
315
|
+
}
|
|
316
|
+
})
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
function publishOwner(owner) {
|
|
320
|
+
if (activeOwner(owner.store) !== owner || !owner.pipeline) return;
|
|
321
|
+
owner.store.setState({ renderPipeline: owner.pipeline, passes: owner.passes });
|
|
322
|
+
setRenderOverride(owner.store, renderThroughPipeline(owner.store));
|
|
323
|
+
}
|
|
324
|
+
function scheduleRelease(owner) {
|
|
325
|
+
owner.mounted = false;
|
|
326
|
+
if (owner.releaseTimer !== null) return;
|
|
327
|
+
owner.releaseTimer = setTimeout(() => releaseOwner(owner));
|
|
328
|
+
}
|
|
329
|
+
function releaseOwner(owner) {
|
|
330
|
+
if (owner.releaseTimer !== null) clearTimeout(owner.releaseTimer);
|
|
331
|
+
owner.releaseTimer = null;
|
|
332
|
+
const { store } = owner;
|
|
333
|
+
const list = owners.get(store);
|
|
334
|
+
const index = list?.indexOf(owner) ?? -1;
|
|
335
|
+
if (list && index !== -1) {
|
|
336
|
+
const wasActive = index === list.length - 1;
|
|
337
|
+
list.splice(index, 1);
|
|
338
|
+
if (wasActive) {
|
|
339
|
+
const next = activeOwner(store);
|
|
340
|
+
if (next) {
|
|
341
|
+
publishOwner(next);
|
|
342
|
+
} else {
|
|
343
|
+
store.setState({ renderPipeline: null, passes: {} });
|
|
344
|
+
setRenderOverride(store, null);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
disposeOwnerResources(owner);
|
|
349
|
+
}
|
|
350
|
+
function releaseAllOwners(store) {
|
|
351
|
+
clearTimeout(sweeps.get(store));
|
|
352
|
+
sweeps.delete(store);
|
|
353
|
+
const list = owners.get(store);
|
|
354
|
+
if (!list) return;
|
|
355
|
+
owners.delete(store);
|
|
356
|
+
for (const owner of list) {
|
|
357
|
+
if (owner.releaseTimer !== null) clearTimeout(owner.releaseTimer);
|
|
358
|
+
owner.releaseTimer = null;
|
|
359
|
+
disposeOwnerResources(owner);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
259
363
|
const SHARED_KEYS = ["uniforms", "nodes", "buffers", "gpuStorage", "_hmrVersion"];
|
|
260
364
|
const following = /* @__PURE__ */ new WeakMap();
|
|
261
365
|
function createResourceState() {
|
|
@@ -284,6 +388,7 @@ function followPrimary(store, primary) {
|
|
|
284
388
|
following.set(store, primary.subscribe(sync));
|
|
285
389
|
}
|
|
286
390
|
function dispose(store) {
|
|
391
|
+
releaseAllOwners(store);
|
|
287
392
|
untrackPrimary(store);
|
|
288
393
|
following.get(store)?.();
|
|
289
394
|
following.delete(store);
|
|
@@ -689,8 +794,9 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
689
794
|
input: memoizedInput,
|
|
690
795
|
create: () => {
|
|
691
796
|
if (isReader) return {};
|
|
692
|
-
if (typeof processedInput.candidates !== "object" || processedInput.candidates === null)
|
|
797
|
+
if (typeof processedInput.candidates !== "object" || processedInput.candidates === null) {
|
|
693
798
|
throw new Error("Invalid uniform input");
|
|
799
|
+
}
|
|
694
800
|
return processedInput.candidates;
|
|
695
801
|
},
|
|
696
802
|
prepare: (name, candidate) => createUniform(name, candidate, scope),
|
|
@@ -708,13 +814,7 @@ function useUniforms(creatorOrScope, scope) {
|
|
|
708
814
|
if (!equals) existing.value = newVal;
|
|
709
815
|
}
|
|
710
816
|
});
|
|
711
|
-
|
|
712
|
-
if (memoizedInput === void 0) {
|
|
713
|
-
uniforms = storeUniforms;
|
|
714
|
-
} else if (typeof memoizedInput === "string") {
|
|
715
|
-
const scopeData = storeUniforms[memoizedInput];
|
|
716
|
-
uniforms = scopeData && !isUniformNode(scopeData) ? scopeData : {};
|
|
717
|
-
}
|
|
817
|
+
const uniforms = isReader ? readWithStaged(store, "uniforms", storeUniforms, memoizedInput, isUniformNode) : created;
|
|
718
818
|
return { ...uniforms, removeUniforms, clearUniforms, rebuildUniforms };
|
|
719
819
|
}
|
|
720
820
|
function rebuildAllUniforms(store, scope) {
|
|
@@ -831,13 +931,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
831
931
|
return node;
|
|
832
932
|
}
|
|
833
933
|
});
|
|
834
|
-
|
|
835
|
-
if (creatorOrScope === void 0) {
|
|
836
|
-
nodes = storeNodes;
|
|
837
|
-
} else if (typeof creatorOrScope === "string") {
|
|
838
|
-
const scopeData = storeNodes[creatorOrScope];
|
|
839
|
-
nodes = scopeData && !isTSLNode(scopeData) ? scopeData : {};
|
|
840
|
-
}
|
|
934
|
+
const nodes = isReader ? readWithStaged(store, "nodes", storeNodes, creatorOrScope, isTSLNode) : created;
|
|
841
935
|
return { ...nodes, removeNodes, clearNodes, rebuildNodes };
|
|
842
936
|
}
|
|
843
937
|
function rebuildAllNodes(store, scope) {
|
|
@@ -992,13 +1086,7 @@ function useBuffers(creatorOrScope, scope) {
|
|
|
992
1086
|
return buffer;
|
|
993
1087
|
}
|
|
994
1088
|
});
|
|
995
|
-
|
|
996
|
-
if (creatorOrScope === void 0) {
|
|
997
|
-
buffers = storeBuffers;
|
|
998
|
-
} else if (typeof creatorOrScope === "string") {
|
|
999
|
-
const scopeData = storeBuffers[creatorOrScope];
|
|
1000
|
-
buffers = scopeData && !isBufferLike(scopeData) ? scopeData : {};
|
|
1001
|
-
}
|
|
1089
|
+
const buffers = isReader ? readWithStaged(store, "buffers", storeBuffers, creatorOrScope, isBufferLike) : created;
|
|
1002
1090
|
return { ...buffers, removeBuffers, clearBuffers, rebuildBuffers, disposeBuffers };
|
|
1003
1091
|
}
|
|
1004
1092
|
function rebuildAllBuffers(store, scope) {
|
|
@@ -1062,13 +1150,7 @@ function useGPUStorage(creatorOrScope, scope) {
|
|
|
1062
1150
|
return storage;
|
|
1063
1151
|
}
|
|
1064
1152
|
});
|
|
1065
|
-
|
|
1066
|
-
if (creatorOrScope === void 0) {
|
|
1067
|
-
gpuStorage = storeStorage;
|
|
1068
|
-
} else if (typeof creatorOrScope === "string") {
|
|
1069
|
-
const scopeData = storeStorage[creatorOrScope];
|
|
1070
|
-
gpuStorage = scopeData && !isStorageLike(scopeData) ? scopeData : {};
|
|
1071
|
-
}
|
|
1153
|
+
const gpuStorage = isReader ? readWithStaged(store, "gpuStorage", storeStorage, creatorOrScope, isStorageLike) : created;
|
|
1072
1154
|
return {
|
|
1073
1155
|
...gpuStorage,
|
|
1074
1156
|
removeStorage,
|
|
@@ -1082,120 +1164,164 @@ function rebuildAllStorage(store, scope) {
|
|
|
1082
1164
|
}
|
|
1083
1165
|
|
|
1084
1166
|
const NO_PASSES = Object.freeze({});
|
|
1085
|
-
function
|
|
1086
|
-
return () => {
|
|
1087
|
-
const pipeline = store.getState().renderPipeline;
|
|
1088
|
-
if (pipeline?.render) pipeline.render();
|
|
1089
|
-
};
|
|
1090
|
-
}
|
|
1091
|
-
function useRenderPipeline(mainCB, setupCB) {
|
|
1167
|
+
function useRenderPipeline(mainCB, setupCB, options) {
|
|
1092
1168
|
const store = useStore();
|
|
1169
|
+
const primary = usePrimaryStore();
|
|
1170
|
+
const view = useMemo(() => createResourceView(primary, store), [primary, store]);
|
|
1093
1171
|
const { scene, camera, renderer, isLegacy } = useThree();
|
|
1172
|
+
const hmrVersion = usePrimaryThree((s) => s._hmrVersion);
|
|
1173
|
+
const isOwner = mainCB !== void 0 || setupCB !== void 0;
|
|
1094
1174
|
const callbacksRanRef = useRef(false);
|
|
1095
|
-
const scenePassCacheRef = useRef(null);
|
|
1096
1175
|
const forceScenePassRebuildRef = useRef(false);
|
|
1097
1176
|
const mainCBRef = useRef(mainCB);
|
|
1098
1177
|
const setupCBRef = useRef(setupCB);
|
|
1178
|
+
const persistRef = useRef(options?.persist ?? false);
|
|
1099
1179
|
mainCBRef.current = mainCB;
|
|
1100
1180
|
setupCBRef.current = setupCB;
|
|
1181
|
+
persistRef.current = options?.persist ?? false;
|
|
1101
1182
|
const [rebuildVersion, setRebuildVersion] = useState(0);
|
|
1102
|
-
|
|
1183
|
+
const rerun = useCallback((freshScenePass) => {
|
|
1103
1184
|
callbacksRanRef.current = false;
|
|
1104
|
-
forceScenePassRebuildRef.current = true;
|
|
1185
|
+
if (freshScenePass) forceScenePassRebuildRef.current = true;
|
|
1186
|
+
setRebuildVersion((v) => v + 1);
|
|
1105
1187
|
}, []);
|
|
1188
|
+
const ownerRef = useRef(null);
|
|
1189
|
+
const target = useCallback(() => (isOwner ? ownerRef.current : activeOwner(store)) ?? null, [isOwner, store]);
|
|
1106
1190
|
const clearPasses = useCallback(() => {
|
|
1107
|
-
|
|
1108
|
-
|
|
1191
|
+
const owner = target();
|
|
1192
|
+
if (!owner) return;
|
|
1193
|
+
owner.passes = {};
|
|
1194
|
+
if (activeOwner(store) === owner) store.setState({ passes: {} });
|
|
1195
|
+
}, [store, target]);
|
|
1109
1196
|
const reset = useCallback(() => {
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
scenePassCacheRef.current?.scenePass.dispose();
|
|
1116
|
-
callbacksRanRef.current = false;
|
|
1117
|
-
scenePassCacheRef.current = null;
|
|
1118
|
-
forceScenePassRebuildRef.current = false;
|
|
1119
|
-
}, [store]);
|
|
1197
|
+
const owner = target();
|
|
1198
|
+
if (!owner) return;
|
|
1199
|
+
releaseOwner(owner);
|
|
1200
|
+
if (owner === ownerRef.current) committedReads.current = null;
|
|
1201
|
+
}, [target]);
|
|
1120
1202
|
const rebuild = useCallback(() => {
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1203
|
+
if (isOwner) rerun(true);
|
|
1204
|
+
else activeOwner(store)?.rebuild();
|
|
1205
|
+
}, [isOwner, rerun, store]);
|
|
1206
|
+
const hmrVersionRef = useRef(hmrVersion);
|
|
1207
|
+
useEffect(() => {
|
|
1208
|
+
if (hmrVersionRef.current === hmrVersion) return;
|
|
1209
|
+
hmrVersionRef.current = hmrVersion;
|
|
1210
|
+
if (isOwner) rerun(false);
|
|
1211
|
+
}, [hmrVersion, isOwner, rerun]);
|
|
1212
|
+
const committedReads = useRef(null);
|
|
1213
|
+
const readsVersion = useRef(0);
|
|
1214
|
+
const getReadsVersion = () => {
|
|
1215
|
+
const tracker = committedReads.current;
|
|
1216
|
+
if (tracker && !tracker.stale && isTrackerStale(tracker, view)) readsVersion.current++;
|
|
1217
|
+
return readsVersion.current;
|
|
1218
|
+
};
|
|
1219
|
+
const subscribe = useCallback(
|
|
1220
|
+
(onChange) => {
|
|
1221
|
+
const unsubscribe = primary.subscribe(onChange);
|
|
1222
|
+
if (store === primary) return unsubscribe;
|
|
1223
|
+
const unsubscribeLocal = store.subscribe(onChange);
|
|
1224
|
+
return () => {
|
|
1225
|
+
unsubscribe();
|
|
1226
|
+
unsubscribeLocal();
|
|
1227
|
+
};
|
|
1228
|
+
},
|
|
1229
|
+
[primary, store]
|
|
1230
|
+
);
|
|
1231
|
+
const resourceVersion = useSyncExternalStore(subscribe, getReadsVersion, getReadsVersion);
|
|
1232
|
+
const lastResourceVersion = useRef(resourceVersion);
|
|
1125
1233
|
useLayoutEffect(() => {
|
|
1126
1234
|
if (isLegacy) {
|
|
1127
|
-
throw new Error(
|
|
1235
|
+
throw new Error(
|
|
1236
|
+
"useRenderPipeline needs WebGPU: import Canvas from @react-three/fiber, not @react-three/fiber/legacy."
|
|
1237
|
+
);
|
|
1128
1238
|
}
|
|
1239
|
+
if (!isOwner) return;
|
|
1129
1240
|
if (!renderer || !scene || !camera) return;
|
|
1130
1241
|
if (!("isWebGPURenderer" in renderer)) {
|
|
1131
1242
|
throw new Error("useRenderPipeline: renderer is not a WebGPURenderer but isLegacy is false.");
|
|
1132
1243
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1244
|
+
let owner = ownerRef.current;
|
|
1245
|
+
if (owner && owner.store !== store) {
|
|
1246
|
+
releaseOwner(owner);
|
|
1247
|
+
owner = null;
|
|
1248
|
+
}
|
|
1249
|
+
if (!owner) owner = ownerRef.current = createOwner(store, () => rerun(true));
|
|
1250
|
+
claimOwnership(owner);
|
|
1251
|
+
const currentOwner = owner;
|
|
1135
1252
|
try {
|
|
1136
|
-
let pipeline = state.renderPipeline ?? null;
|
|
1137
|
-
let currentPasses = { ...state.passes };
|
|
1138
1253
|
let justCreatedPipeline = false;
|
|
1139
|
-
if (!pipeline) {
|
|
1140
|
-
|
|
1254
|
+
if (!owner.pipeline || owner.pipeline.renderer !== renderer) {
|
|
1255
|
+
disposeOwnerResources(owner);
|
|
1256
|
+
owner.pipeline = new THREE.RenderPipeline(renderer);
|
|
1141
1257
|
justCreatedPipeline = true;
|
|
1142
1258
|
}
|
|
1143
|
-
const
|
|
1259
|
+
const pipeline = owner.pipeline;
|
|
1260
|
+
const cached = owner.scenePass;
|
|
1261
|
+
const cacheValid = !forceScenePassRebuildRef.current && cached !== null && cached.sceneUuid === scene.uuid && cached.cameraUuid === camera.uuid;
|
|
1144
1262
|
let outgoingScenePass = null;
|
|
1145
1263
|
let scenePass;
|
|
1146
|
-
if (cacheValid) {
|
|
1147
|
-
scenePass =
|
|
1264
|
+
if (cacheValid && cached) {
|
|
1265
|
+
scenePass = cached.node;
|
|
1148
1266
|
} else {
|
|
1149
|
-
outgoingScenePass =
|
|
1267
|
+
outgoingScenePass = cached?.node ?? null;
|
|
1150
1268
|
scenePass = pass(scene, camera);
|
|
1151
|
-
|
|
1269
|
+
owner.scenePass = { sceneUuid: scene.uuid, cameraUuid: camera.uuid, node: scenePass };
|
|
1152
1270
|
forceScenePassRebuildRef.current = false;
|
|
1153
1271
|
}
|
|
1154
|
-
currentPasses.scenePass = scenePass;
|
|
1155
1272
|
let outputNodeChanged = false;
|
|
1156
1273
|
if (!pipeline.outputNode || justCreatedPipeline || pipeline.outputNode === outgoingScenePass) {
|
|
1157
1274
|
pipeline.outputNode = scenePass;
|
|
1158
1275
|
outputNodeChanged = true;
|
|
1159
1276
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
const shouldRunCallbacks = justCreatedPipeline || !callbacksRanRef.current || !cacheValid;
|
|
1277
|
+
const readsChanged = lastResourceVersion.current !== resourceVersion;
|
|
1278
|
+
lastResourceVersion.current = resourceVersion;
|
|
1279
|
+
const shouldRunCallbacks = justCreatedPipeline || !callbacksRanRef.current || !cacheValid || readsChanged;
|
|
1163
1280
|
if (shouldRunCallbacks) {
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1281
|
+
let currentPasses = { scenePass };
|
|
1282
|
+
owner.passes = currentPasses;
|
|
1283
|
+
const tracker = createReadTracker("useRenderPipeline");
|
|
1284
|
+
const callbackState = () => Object.assign(
|
|
1285
|
+
createLazyCreatorState(store.getState(), primary, {
|
|
1286
|
+
reads: { observe: tracker.observe, nested: true },
|
|
1287
|
+
view
|
|
1288
|
+
}),
|
|
1289
|
+
{ renderPipeline: pipeline, passes: { ...currentPasses, scenePass }, renderer, isLegacy: false }
|
|
1290
|
+
);
|
|
1291
|
+
try {
|
|
1292
|
+
if (setupCBRef.current) {
|
|
1293
|
+
const setupResult = setupCBRef.current(callbackState());
|
|
1294
|
+
if (setupResult && typeof setupResult === "object") {
|
|
1295
|
+
currentPasses = { ...currentPasses, ...setupResult };
|
|
1296
|
+
owner.passes = currentPasses;
|
|
1297
|
+
}
|
|
1175
1298
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
isLegacy: false
|
|
1183
|
-
});
|
|
1184
|
-
const mainResult = mainCBRef.current(freshState);
|
|
1185
|
-
if (mainResult && typeof mainResult === "object") {
|
|
1186
|
-
currentPasses = { ...currentPasses, ...mainResult };
|
|
1187
|
-
set({ passes: currentPasses });
|
|
1299
|
+
if (mainCBRef.current) {
|
|
1300
|
+
const mainResult = mainCBRef.current(callbackState());
|
|
1301
|
+
if (mainResult && typeof mainResult === "object") {
|
|
1302
|
+
currentPasses = { ...currentPasses, ...mainResult };
|
|
1303
|
+
owner.passes = currentPasses;
|
|
1304
|
+
}
|
|
1188
1305
|
}
|
|
1306
|
+
} finally {
|
|
1307
|
+
tracker.closed = true;
|
|
1308
|
+
committedReads.current = tracker;
|
|
1189
1309
|
}
|
|
1190
1310
|
outputNodeChanged = true;
|
|
1191
1311
|
callbacksRanRef.current = true;
|
|
1192
1312
|
}
|
|
1193
1313
|
if (outputNodeChanged) pipeline.needsUpdate = true;
|
|
1314
|
+
publishOwner(owner);
|
|
1194
1315
|
if (outgoingScenePass && outgoingScenePass !== scenePass) outgoingScenePass.dispose();
|
|
1195
1316
|
} catch (error) {
|
|
1317
|
+
publishOwner(owner);
|
|
1196
1318
|
console.warn("[useRenderPipeline] Setup failed; the render pipeline was not configured:", error);
|
|
1197
1319
|
}
|
|
1198
|
-
|
|
1320
|
+
return () => {
|
|
1321
|
+
if (persistRef.current) currentOwner.mounted = false;
|
|
1322
|
+
else scheduleRelease(currentOwner);
|
|
1323
|
+
};
|
|
1324
|
+
}, [store, primary, view, renderer, scene, camera, isLegacy, isOwner, rebuildVersion, resourceVersion, rerun]);
|
|
1199
1325
|
const passes = useThree((s) => s.passes) ?? NO_PASSES;
|
|
1200
1326
|
const renderPipeline = useThree((s) => s.renderPipeline) ?? null;
|
|
1201
1327
|
const actions = { passes, clearPasses, reset, rebuild };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-three/tsl",
|
|
3
|
-
"version": "10.0.0-canary.
|
|
3
|
+
"version": "10.0.0-canary.88b1ca7",
|
|
4
4
|
"description": "TSL resource hooks for react-three-fiber: uniforms, nodes, buffers, GPU storage and render pipelines on WebGPU",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@types/three": "^0.185.0",
|
|
57
57
|
"@webgpu/types": "^0.1.64",
|
|
58
58
|
"three": ">=0.185.0",
|
|
59
|
-
"@react-three/fiber": "10.0.0-canary.
|
|
59
|
+
"@react-three/fiber": "10.0.0-canary.88b1ca7"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"build": "unbuild",
|
package/readme.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
TSL resource hooks for [react-three-fiber](https://github.com/pmndrs/react-three-fiber) on WebGPU: shared uniforms, nodes, buffers, GPU storage and render pipelines.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @react-three/tsl
|
|
6
|
+
npm install @react-three/tsl@alpha
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
```tsx
|
|
@@ -32,7 +32,7 @@ function Driver() {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export const App = () => (
|
|
35
|
-
<Canvas
|
|
35
|
+
<Canvas>
|
|
36
36
|
<Wobble />
|
|
37
37
|
<Driver />
|
|
38
38
|
</Canvas>
|
|
@@ -48,6 +48,6 @@ export const App = () => (
|
|
|
48
48
|
|
|
49
49
|
Resources belong to the renderer: a `<Canvas primary>`, the canvases sharing its renderer (every other WebGPU canvas, or `share="id"`) and every portal inside them share one set. They live on the primary canvas's `RootState` (`state.uniforms`, `state.nodes`, `state.buffers`, `state.gpuStorage`); secondaries hold the same objects and portals inherit them from their parent (a portal's scene and camera stay its own), so `state.uniforms` reads the same everywhere.
|
|
50
50
|
|
|
51
|
-
Works under any Canvas that runs the WebGPU renderer: `@react-three/fiber`
|
|
51
|
+
Works under any Canvas that runs the WebGPU renderer: `@react-three/fiber` or `@react-three/fiber/webgpu` (not `/legacy`). It reaches fiber only through the three-free `@react-three/fiber/extension` entry, so it adds no renderer and no second copy of fiber to your bundle.
|
|
52
52
|
|
|
53
53
|
Full documentation: [WebGPU & TSL](https://github.com/pmndrs/react-three-fiber/tree/v10/docs/webgpu).
|