@react-three/fiber 8.2.0 → 9.0.0-alpha.0
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/CHANGELOG.md +12 -0
- package/dist/declarations/src/core/events.d.ts +69 -69
- package/dist/declarations/src/core/hooks.d.ts +23 -21
- package/dist/declarations/src/core/index.d.ts +61 -57
- package/dist/declarations/src/core/loop.d.ts +13 -13
- package/dist/declarations/src/core/renderer.d.ts +51 -51
- package/dist/declarations/src/core/stages.d.ts +59 -0
- package/dist/declarations/src/core/store.d.ts +110 -95
- package/dist/declarations/src/core/utils.d.ts +81 -82
- package/dist/declarations/src/index.d.ts +12 -11
- package/dist/declarations/src/native/Canvas.d.ts +8 -8
- package/dist/declarations/src/native/events.d.ts +4 -4
- package/dist/declarations/src/native/polyfills.d.ts +1 -1
- package/dist/declarations/src/native.d.ts +10 -10
- package/dist/declarations/src/three-types.d.ts +331 -331
- package/dist/declarations/src/web/Canvas.d.ts +9 -9
- package/dist/declarations/src/web/events.d.ts +4 -4
- package/dist/{index-ca47b633.cjs.prod.js → index-b12f488b.cjs.prod.js} +290 -69
- package/dist/{index-0499a96a.cjs.dev.js → index-b3be5a63.cjs.dev.js} +290 -69
- package/dist/{index-6279214a.esm.js → index-e27d4a05.esm.js} +287 -70
- package/dist/react-three-fiber.cjs.dev.js +7 -1
- package/dist/react-three-fiber.cjs.prod.js +7 -1
- package/dist/react-three-fiber.esm.js +4 -2
- package/native/dist/react-three-fiber-native.cjs.dev.js +4 -1
- package/native/dist/react-three-fiber-native.cjs.prod.js +4 -1
- package/native/dist/react-three-fiber-native.esm.js +4 -2
- package/package.json +6 -6
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import type { Options as ResizeOptions } from 'react-use-measure';
|
|
3
|
-
import { RenderProps } from '../core';
|
|
4
|
-
export interface Props extends Omit<RenderProps<HTMLCanvasElement>, 'size'>, React.HTMLAttributes<HTMLDivElement> {
|
|
5
|
-
children: React.ReactNode;
|
|
6
|
-
fallback?: React.ReactNode;
|
|
7
|
-
resize?: ResizeOptions;
|
|
8
|
-
}
|
|
9
|
-
export declare const Canvas: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLCanvasElement>>;
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { Options as ResizeOptions } from 'react-use-measure';
|
|
3
|
+
import { RenderProps } from '../core';
|
|
4
|
+
export interface Props extends Omit<RenderProps<HTMLCanvasElement>, 'size'>, React.HTMLAttributes<HTMLDivElement> {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
fallback?: React.ReactNode;
|
|
7
|
+
resize?: ResizeOptions;
|
|
8
|
+
}
|
|
9
|
+
export declare const Canvas: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLCanvasElement>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UseBoundStore } from 'zustand';
|
|
2
|
-
import { RootState } from '../core/store';
|
|
3
|
-
import { EventManager } from '../core/events';
|
|
4
|
-
export declare function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement>;
|
|
1
|
+
import { UseBoundStore } from 'zustand';
|
|
2
|
+
import { RootState } from '../core/store';
|
|
3
|
+
import { EventManager } from '../core/events';
|
|
4
|
+
export declare function createPointerEvents(store: UseBoundStore<RootState>): EventManager<HTMLElement>;
|
|
@@ -37,12 +37,19 @@ var threeTypes = /*#__PURE__*/Object.freeze({
|
|
|
37
37
|
__proto__: null
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
var _window$document, _window$navigator;
|
|
41
|
+
const isOrthographicCamera = def => def && def.isOrthographicCamera;
|
|
42
|
+
/**
|
|
43
|
+
* An SSR-friendly useLayoutEffect.
|
|
44
|
+
*
|
|
45
|
+
* React currently throws a warning when using useLayoutEffect on the server.
|
|
46
|
+
* To get around it, we can conditionally useEffect on the server (no-op) and
|
|
47
|
+
* useLayoutEffect elsewhere.
|
|
48
|
+
*
|
|
49
|
+
* @see https://github.com/facebook/react/issues/14927
|
|
50
|
+
*/
|
|
43
51
|
|
|
44
|
-
const
|
|
45
|
-
const useIsomorphicLayoutEffect = isSSR ? React__namespace.useEffect : React__namespace.useLayoutEffect;
|
|
52
|
+
const useIsomorphicLayoutEffect = typeof window !== 'undefined' && ((_window$document = window.document) != null && _window$document.createElement || ((_window$navigator = window.navigator) == null ? void 0 : _window$navigator.product) === 'ReactNative') ? React__namespace.useLayoutEffect : React__namespace.useEffect;
|
|
46
53
|
function useMutableCallback(fn) {
|
|
47
54
|
const ref = React__namespace.useRef(fn);
|
|
48
55
|
useIsomorphicLayoutEffect(() => void (ref.current = fn), [fn]);
|
|
@@ -358,12 +365,7 @@ function applyProps$1(instance, data) {
|
|
|
358
365
|
|
|
359
366
|
if (!isColor && targetProp.setScalar) targetProp.setScalar(value); // Layers have no copy function, we must therefore copy the mask property
|
|
360
367
|
else if (targetProp instanceof THREE__namespace.Layers && value instanceof THREE__namespace.Layers) targetProp.mask = value.mask; // Otherwise just set ...
|
|
361
|
-
else targetProp.set(value);
|
|
362
|
-
// Auto-convert sRGB colors
|
|
363
|
-
// https://github.com/pmndrs/react-three-fiber/issues/344
|
|
364
|
-
|
|
365
|
-
const supportsColorManagement = ('ColorManagement' in THREE__namespace);
|
|
366
|
-
if (!supportsColorManagement && !rootState.linear && isColor) targetProp.convertSRGBToLinear();
|
|
368
|
+
else targetProp.set(value);
|
|
367
369
|
} // Else, just overwrite the value
|
|
368
370
|
|
|
369
371
|
} else {
|
|
@@ -418,15 +420,6 @@ function updateCamera(camera, size) {
|
|
|
418
420
|
camera.updateMatrixWorld();
|
|
419
421
|
}
|
|
420
422
|
}
|
|
421
|
-
/**
|
|
422
|
-
* Safely sets a deeply-nested value on an object.
|
|
423
|
-
*/
|
|
424
|
-
|
|
425
|
-
function setDeep(obj, value, keys) {
|
|
426
|
-
const key = keys.pop();
|
|
427
|
-
const target = keys.reduce((acc, key) => acc[key], obj);
|
|
428
|
-
return target[key] = value;
|
|
429
|
-
}
|
|
430
423
|
|
|
431
424
|
function makeId(event) {
|
|
432
425
|
return (event.eventObject || event.object).uuid + '/' + event.index + event.instanceId;
|
|
@@ -1063,7 +1056,10 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1063
1056
|
}
|
|
1064
1057
|
}
|
|
1065
1058
|
});
|
|
1066
|
-
}
|
|
1059
|
+
} // Don't handle text instances, warn on undefined behavior
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
const handleTextInstance = () => console.warn('Text is not allowed in the R3F tree! This could be stray whitespace or characters.');
|
|
1067
1063
|
|
|
1068
1064
|
const reconciler = Reconciler__default["default"]({
|
|
1069
1065
|
createInstance,
|
|
@@ -1077,13 +1073,20 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1077
1073
|
supportsHydration: false,
|
|
1078
1074
|
noTimeout: -1,
|
|
1079
1075
|
appendChildToContainer: (container, child) => {
|
|
1076
|
+
if (!child) return;
|
|
1080
1077
|
const scene = container.getState().scene; // Link current root to the default scene
|
|
1081
1078
|
|
|
1082
1079
|
scene.__r3f.root = container;
|
|
1083
1080
|
appendChild(scene, child);
|
|
1084
1081
|
},
|
|
1085
|
-
removeChildFromContainer: (container, child) =>
|
|
1086
|
-
|
|
1082
|
+
removeChildFromContainer: (container, child) => {
|
|
1083
|
+
if (!child) return;
|
|
1084
|
+
removeChild(container.getState().scene, child);
|
|
1085
|
+
},
|
|
1086
|
+
insertInContainerBefore: (container, child, beforeChild) => {
|
|
1087
|
+
if (!child || !beforeChild) return;
|
|
1088
|
+
insertBefore(container.getState().scene, child, beforeChild);
|
|
1089
|
+
},
|
|
1087
1090
|
getRootHostContext: () => null,
|
|
1088
1091
|
getChildHostContext: parentHostContext => parentHostContext,
|
|
1089
1092
|
|
|
@@ -1175,13 +1178,9 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1175
1178
|
invalidateInstance(instance);
|
|
1176
1179
|
},
|
|
1177
1180
|
|
|
1178
|
-
createTextInstance:
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
hideTextInstance: () => {
|
|
1182
|
-
throw new Error('Text is not allowed in the R3F tree.');
|
|
1183
|
-
},
|
|
1184
|
-
unhideTextInstance: () => {},
|
|
1181
|
+
createTextInstance: handleTextInstance,
|
|
1182
|
+
hideTextInstance: handleTextInstance,
|
|
1183
|
+
unhideTextInstance: handleTextInstance,
|
|
1185
1184
|
// https://github.com/pmndrs/react-three-fiber/pull/2360#discussion_r916356874
|
|
1186
1185
|
// @ts-ignore
|
|
1187
1186
|
getCurrentEventPriority: () => _getEventPriority ? _getEventPriority() : constants.DefaultEventPriority,
|
|
@@ -1199,6 +1198,7 @@ function createRenderer(_roots, _getEventPriority) {
|
|
|
1199
1198
|
};
|
|
1200
1199
|
}
|
|
1201
1200
|
|
|
1201
|
+
// Keys that shouldn't be copied between R3F stores
|
|
1202
1202
|
const privateKeys = ['set', 'get', 'setSize', 'setFrameloop', 'setDpr', 'events', 'invalidate', 'advance', 'size', 'viewport'];
|
|
1203
1203
|
const isRenderer = def => !!(def != null && def.render);
|
|
1204
1204
|
const context = /*#__PURE__*/React__namespace.createContext(null);
|
|
@@ -1346,8 +1346,14 @@ const createStore = (invalidate, advance) => {
|
|
|
1346
1346
|
}
|
|
1347
1347
|
};
|
|
1348
1348
|
}),
|
|
1349
|
-
setFrameloop:
|
|
1350
|
-
|
|
1349
|
+
setFrameloop: frameloop => {
|
|
1350
|
+
var _frameloop$mode, _frameloop$render, _frameloop$maxDelta;
|
|
1351
|
+
|
|
1352
|
+
const state = get();
|
|
1353
|
+
const mode = typeof frameloop === 'string' ? frameloop : (frameloop == null ? void 0 : frameloop.mode) === 'auto' ? 'always' : (_frameloop$mode = frameloop == null ? void 0 : frameloop.mode) != null ? _frameloop$mode : state.frameloop;
|
|
1354
|
+
const render = typeof frameloop === 'string' ? state.internal.render : (_frameloop$render = frameloop == null ? void 0 : frameloop.render) != null ? _frameloop$render : state.internal.render;
|
|
1355
|
+
const maxDelta = typeof frameloop === 'string' ? state.internal.maxDelta : (_frameloop$maxDelta = frameloop == null ? void 0 : frameloop.maxDelta) != null ? _frameloop$maxDelta : state.internal.maxDelta;
|
|
1356
|
+
const clock = state.clock; // if frameloop === "never" clock.elapsedTime is updated using advance(timestamp)
|
|
1351
1357
|
|
|
1352
1358
|
clock.stop();
|
|
1353
1359
|
clock.elapsedTime = 0;
|
|
@@ -1358,28 +1364,44 @@ const createStore = (invalidate, advance) => {
|
|
|
1358
1364
|
}
|
|
1359
1365
|
|
|
1360
1366
|
set(() => ({
|
|
1361
|
-
frameloop
|
|
1367
|
+
frameloop: mode,
|
|
1368
|
+
internal: { ...state.internal,
|
|
1369
|
+
render,
|
|
1370
|
+
maxDelta
|
|
1371
|
+
}
|
|
1362
1372
|
}));
|
|
1363
1373
|
},
|
|
1364
1374
|
previousRoot: undefined,
|
|
1365
1375
|
internal: {
|
|
1366
|
-
|
|
1367
|
-
priority: 0,
|
|
1368
|
-
frames: 0,
|
|
1369
|
-
lastEvent: /*#__PURE__*/React__namespace.createRef(),
|
|
1376
|
+
// Events
|
|
1370
1377
|
interaction: [],
|
|
1371
1378
|
hovered: new Map(),
|
|
1372
1379
|
subscribers: [],
|
|
1373
1380
|
initialClick: [0, 0],
|
|
1374
1381
|
initialHits: [],
|
|
1375
1382
|
capturedMap: new Map(),
|
|
1383
|
+
lastEvent: /*#__PURE__*/React__namespace.createRef(),
|
|
1384
|
+
// Updates
|
|
1385
|
+
active: false,
|
|
1386
|
+
frames: 0,
|
|
1387
|
+
stages: [],
|
|
1388
|
+
render: 'auto',
|
|
1389
|
+
maxDelta: 1 / 10,
|
|
1390
|
+
priority: 0,
|
|
1376
1391
|
subscribe: (ref, priority, store) => {
|
|
1377
|
-
const
|
|
1392
|
+
const state = get();
|
|
1393
|
+
const internal = state.internal; // If this subscription was given a priority, it takes rendering into its own hands
|
|
1378
1394
|
// For that reason we switch off automatic rendering and increase the manual flag
|
|
1379
1395
|
// As long as this flag is positive there can be no internal rendering at all
|
|
1380
1396
|
// because there could be multiple render subscriptions
|
|
1381
1397
|
|
|
1382
|
-
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1398
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0); // We use the render flag and deprecate priority
|
|
1399
|
+
|
|
1400
|
+
if (internal.priority && state.internal.render === 'auto') set(() => ({
|
|
1401
|
+
internal: { ...state.internal,
|
|
1402
|
+
render: 'manual'
|
|
1403
|
+
}
|
|
1404
|
+
}));
|
|
1383
1405
|
internal.subscribers.push({
|
|
1384
1406
|
ref,
|
|
1385
1407
|
priority,
|
|
@@ -1389,11 +1411,18 @@ const createStore = (invalidate, advance) => {
|
|
|
1389
1411
|
|
|
1390
1412
|
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
1391
1413
|
return () => {
|
|
1392
|
-
const
|
|
1414
|
+
const state = get();
|
|
1415
|
+
const internal = state.internal;
|
|
1393
1416
|
|
|
1394
1417
|
if (internal != null && internal.subscribers) {
|
|
1395
1418
|
// Decrease manual flag if this subscription had a priority
|
|
1396
|
-
internal.priority = internal.priority - (priority > 0 ? 1 : 0); //
|
|
1419
|
+
internal.priority = internal.priority - (priority > 0 ? 1 : 0); // We use the render flag and deprecate priority
|
|
1420
|
+
|
|
1421
|
+
if (!internal.priority && state.internal.render === 'manual') set(() => ({
|
|
1422
|
+
internal: { ...state.internal,
|
|
1423
|
+
render: 'auto'
|
|
1424
|
+
}
|
|
1425
|
+
})); // Remove subscriber from list
|
|
1397
1426
|
|
|
1398
1427
|
internal.subscribers = internal.subscribers.filter(s => s.ref !== ref);
|
|
1399
1428
|
}
|
|
@@ -1449,8 +1478,6 @@ function createSubs(callback, subs) {
|
|
|
1449
1478
|
subs.add(sub);
|
|
1450
1479
|
return () => void subs.delete(sub);
|
|
1451
1480
|
}
|
|
1452
|
-
|
|
1453
|
-
let i;
|
|
1454
1481
|
let globalEffects = new Set();
|
|
1455
1482
|
let globalAfterEffects = new Set();
|
|
1456
1483
|
let globalTailEffects = new Set();
|
|
@@ -1479,10 +1506,7 @@ function run(effects, timestamp) {
|
|
|
1479
1506
|
}) => callback(timestamp));
|
|
1480
1507
|
}
|
|
1481
1508
|
|
|
1482
|
-
|
|
1483
|
-
let subscription;
|
|
1484
|
-
|
|
1485
|
-
function render$1(timestamp, state, frame) {
|
|
1509
|
+
function update(timestamp, state, frame) {
|
|
1486
1510
|
// Run local effects
|
|
1487
1511
|
let delta = state.clock.getDelta(); // In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
1488
1512
|
|
|
@@ -1490,18 +1514,14 @@ function render$1(timestamp, state, frame) {
|
|
|
1490
1514
|
delta = timestamp - state.clock.elapsedTime;
|
|
1491
1515
|
state.clock.oldTime = state.clock.elapsedTime;
|
|
1492
1516
|
state.clock.elapsedTime = timestamp;
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
subscribers = state.internal.subscribers;
|
|
1517
|
+
} else {
|
|
1518
|
+
delta = Math.max(Math.min(delta, state.internal.maxDelta), 0);
|
|
1519
|
+
} // Call subscribers (useUpdate)
|
|
1497
1520
|
|
|
1498
|
-
for (i = 0; i < subscribers.length; i++) {
|
|
1499
|
-
subscription = subscribers[i];
|
|
1500
|
-
subscription.ref.current(subscription.store.getState(), delta, frame);
|
|
1501
|
-
} // Render content
|
|
1502
1521
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1522
|
+
for (const stage of state.internal.stages) {
|
|
1523
|
+
stage.frame(delta, frame);
|
|
1524
|
+
}
|
|
1505
1525
|
|
|
1506
1526
|
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
1507
1527
|
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
@@ -1526,7 +1546,7 @@ function createLoop(roots) {
|
|
|
1526
1546
|
state = root.store.getState(); // If the frameloop is invalidated, do not run another frame
|
|
1527
1547
|
|
|
1528
1548
|
if (state.internal.active && (state.frameloop === 'always' || state.internal.frames > 0) && !((_state$gl$xr = state.gl.xr) != null && _state$gl$xr.isPresenting)) {
|
|
1529
|
-
repeat +=
|
|
1549
|
+
repeat += update(timestamp, state);
|
|
1530
1550
|
}
|
|
1531
1551
|
}); // Run after-effects
|
|
1532
1552
|
|
|
@@ -1557,7 +1577,7 @@ function createLoop(roots) {
|
|
|
1557
1577
|
|
|
1558
1578
|
function advance(timestamp, runGlobalEffects = true, state, frame) {
|
|
1559
1579
|
if (runGlobalEffects) run(globalEffects, timestamp);
|
|
1560
|
-
if (!state) roots.forEach(root =>
|
|
1580
|
+
if (!state) roots.forEach(root => update(timestamp, root.store.getState()));else update(timestamp, state, frame);
|
|
1561
1581
|
if (runGlobalEffects) run(globalAfterEffects, timestamp);
|
|
1562
1582
|
}
|
|
1563
1583
|
|
|
@@ -1578,6 +1598,154 @@ function createLoop(roots) {
|
|
|
1578
1598
|
};
|
|
1579
1599
|
}
|
|
1580
1600
|
|
|
1601
|
+
/**
|
|
1602
|
+
* Class representing a stage that updates every frame.
|
|
1603
|
+
* Stages are used to build a lifecycle of effects for an app's frameloop.
|
|
1604
|
+
*/
|
|
1605
|
+
class Stage {
|
|
1606
|
+
constructor() {
|
|
1607
|
+
this.subscribers = [];
|
|
1608
|
+
this._frameTime = 0;
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* Executes all callback subscriptions on the stage.
|
|
1612
|
+
* @param delta - Delta time between frame calls.
|
|
1613
|
+
* @param [frame] - The XR frame if it exists.
|
|
1614
|
+
*/
|
|
1615
|
+
|
|
1616
|
+
|
|
1617
|
+
frame(delta, frame) {
|
|
1618
|
+
const subs = this.subscribers;
|
|
1619
|
+
const initialTime = performance.now();
|
|
1620
|
+
|
|
1621
|
+
for (let i = 0; i < subs.length; i++) {
|
|
1622
|
+
subs[i].ref.current(subs[i].store.getState(), delta, frame);
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
this._frameTime = performance.now() - initialTime;
|
|
1626
|
+
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Adds a callback subscriber to the stage.
|
|
1629
|
+
* @param ref - The mutable callback reference.
|
|
1630
|
+
* @param store - The store to be used with the callback execution.
|
|
1631
|
+
* @returns A function to remove the subscription.
|
|
1632
|
+
*/
|
|
1633
|
+
|
|
1634
|
+
|
|
1635
|
+
add(ref, store) {
|
|
1636
|
+
this.subscribers.push({
|
|
1637
|
+
ref,
|
|
1638
|
+
store
|
|
1639
|
+
});
|
|
1640
|
+
return () => {
|
|
1641
|
+
this.subscribers = this.subscribers.filter(sub => {
|
|
1642
|
+
return sub.ref !== ref;
|
|
1643
|
+
});
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
get frameTime() {
|
|
1648
|
+
return this._frameTime;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
} // Using Unity's fixedStep default.
|
|
1652
|
+
|
|
1653
|
+
const FPS_50 = 1 / 50;
|
|
1654
|
+
/**
|
|
1655
|
+
* Class representing a stage that updates every frame at a fixed rate.
|
|
1656
|
+
* @param name - Name of the stage.
|
|
1657
|
+
* @param [fixedStep] - Fixed step rate.
|
|
1658
|
+
* @param [maxSubsteps] - Maximum number of substeps.
|
|
1659
|
+
*/
|
|
1660
|
+
|
|
1661
|
+
class FixedStage extends Stage {
|
|
1662
|
+
constructor(fixedStep, maxSubSteps) {
|
|
1663
|
+
super();
|
|
1664
|
+
this._fixedStep = fixedStep != null ? fixedStep : FPS_50;
|
|
1665
|
+
this._maxSubsteps = maxSubSteps != null ? maxSubSteps : 6;
|
|
1666
|
+
this._accumulator = 0;
|
|
1667
|
+
this._alpha = 0;
|
|
1668
|
+
this._fixedFrameTime = 0;
|
|
1669
|
+
this._substepTimes = [];
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Executes all callback subscriptions on the stage.
|
|
1673
|
+
* @param delta - Delta time between frame calls.
|
|
1674
|
+
* @param [frame] - The XR frame if it exists.
|
|
1675
|
+
*/
|
|
1676
|
+
|
|
1677
|
+
|
|
1678
|
+
frame(delta, frame) {
|
|
1679
|
+
const initialTime = performance.now();
|
|
1680
|
+
let substeps = 0;
|
|
1681
|
+
this._substepTimes = [];
|
|
1682
|
+
this._accumulator += delta;
|
|
1683
|
+
|
|
1684
|
+
while (this._accumulator >= this._fixedStep && substeps < this._maxSubsteps) {
|
|
1685
|
+
this._accumulator -= this._fixedStep;
|
|
1686
|
+
substeps++;
|
|
1687
|
+
super.frame(this._fixedStep, frame);
|
|
1688
|
+
|
|
1689
|
+
this._substepTimes.push(super.frameTime);
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
this._fixedFrameTime = performance.now() - initialTime; // The accumulator will only be larger than the fixed step if we had to
|
|
1693
|
+
// bail early due to hitting the max substep limit or execution time lagging.
|
|
1694
|
+
// In that case, we want to shave off the excess so we don't fall behind next frame.
|
|
1695
|
+
|
|
1696
|
+
this._accumulator = this._accumulator % this._fixedStep;
|
|
1697
|
+
this._alpha = this._accumulator / this._fixedStep;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
get frameTime() {
|
|
1701
|
+
return this._fixedFrameTime;
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
get substepTimes() {
|
|
1705
|
+
return this._substepTimes;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
get fixedStep() {
|
|
1709
|
+
return this._fixedStep;
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
set fixedStep(fixedStep) {
|
|
1713
|
+
this._fixedStep = fixedStep;
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
get maxSubsteps() {
|
|
1717
|
+
return this._maxSubsteps;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
set maxSubsteps(maxSubsteps) {
|
|
1721
|
+
this._maxSubsteps = maxSubsteps;
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
get accumulator() {
|
|
1725
|
+
return this._accumulator;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
get alpha() {
|
|
1729
|
+
return this._alpha;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
}
|
|
1733
|
+
const Early = new Stage();
|
|
1734
|
+
const Fixed = new FixedStage();
|
|
1735
|
+
const Update = new Stage();
|
|
1736
|
+
const Late = new Stage();
|
|
1737
|
+
const Render = new Stage();
|
|
1738
|
+
const After = new Stage();
|
|
1739
|
+
const Stages = {
|
|
1740
|
+
Early,
|
|
1741
|
+
Fixed,
|
|
1742
|
+
Update,
|
|
1743
|
+
Late,
|
|
1744
|
+
Render,
|
|
1745
|
+
After
|
|
1746
|
+
};
|
|
1747
|
+
const Lifecycle = [Early, Fixed, Update, Late, Render, After];
|
|
1748
|
+
|
|
1581
1749
|
function useStore() {
|
|
1582
1750
|
const store = React__namespace.useContext(context);
|
|
1583
1751
|
if (!store) throw `R3F hooks can only be used within the Canvas component!`;
|
|
@@ -1606,6 +1774,21 @@ function useFrame(callback, renderPriority = 0) {
|
|
|
1606
1774
|
useIsomorphicLayoutEffect(() => subscribe(ref, renderPriority, store), [renderPriority, subscribe, store]);
|
|
1607
1775
|
return null;
|
|
1608
1776
|
}
|
|
1777
|
+
/**
|
|
1778
|
+
* Executes a callback in a given update stage.
|
|
1779
|
+
* Uses the stage instance to indetify which stage to target in the lifecycle.
|
|
1780
|
+
*/
|
|
1781
|
+
|
|
1782
|
+
function useUpdate(callback, stage = Stages.Update) {
|
|
1783
|
+
const store = useStore();
|
|
1784
|
+
const stages = store.getState().internal.stages; // Memoize ref
|
|
1785
|
+
|
|
1786
|
+
const ref = useMutableCallback(callback); // Throw an error if a stage does not exist in the lifecycle
|
|
1787
|
+
|
|
1788
|
+
if (!stages.includes(stage)) throw new Error(`An invoked stage does not exist in the lifecycle.`); // Subscribe on mount, unsubscribe on unmount
|
|
1789
|
+
|
|
1790
|
+
useIsomorphicLayoutEffect(() => stage.add(ref, store), [stage]);
|
|
1791
|
+
}
|
|
1609
1792
|
/**
|
|
1610
1793
|
* Returns a node graph of an object with named nodes & materials.
|
|
1611
1794
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usegraph
|
|
@@ -1687,6 +1870,43 @@ const createRendererInstance = (gl, canvas) => {
|
|
|
1687
1870
|
});
|
|
1688
1871
|
};
|
|
1689
1872
|
|
|
1873
|
+
const createStages = (stages, store) => {
|
|
1874
|
+
var _stages;
|
|
1875
|
+
|
|
1876
|
+
const state = store.getState();
|
|
1877
|
+
let subscribers;
|
|
1878
|
+
let subscription;
|
|
1879
|
+
stages = (_stages = stages) != null ? _stages : Lifecycle;
|
|
1880
|
+
if (!stages.includes(Stages.Update)) throw 'The Stages.Update stage is required for R3F.';
|
|
1881
|
+
if (!stages.includes(Stages.Render)) throw 'The Stages.Render stage is required for R3F.';
|
|
1882
|
+
state.set(({
|
|
1883
|
+
internal
|
|
1884
|
+
}) => ({
|
|
1885
|
+
internal: { ...internal,
|
|
1886
|
+
stages: stages
|
|
1887
|
+
}
|
|
1888
|
+
})); // Add useFrame loop to update stage
|
|
1889
|
+
|
|
1890
|
+
const frameCallback = {
|
|
1891
|
+
current: (state, delta, frame) => {
|
|
1892
|
+
subscribers = state.internal.subscribers;
|
|
1893
|
+
|
|
1894
|
+
for (let i = 0; i < subscribers.length; i++) {
|
|
1895
|
+
subscription = subscribers[i];
|
|
1896
|
+
subscription.ref.current(subscription.store.getState(), delta, frame);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
Stages.Update.add(frameCallback, store); // Add render callback to render stage
|
|
1901
|
+
|
|
1902
|
+
const renderCallback = {
|
|
1903
|
+
current: state => {
|
|
1904
|
+
if (state.internal.render === 'auto' && state.gl.render) state.gl.render(state.scene, state.camera);
|
|
1905
|
+
}
|
|
1906
|
+
};
|
|
1907
|
+
Stages.Render.add(renderCallback, store);
|
|
1908
|
+
};
|
|
1909
|
+
|
|
1690
1910
|
function createRoot(canvas) {
|
|
1691
1911
|
// Check against mistaken use of createRoot
|
|
1692
1912
|
let prevRoot = roots.get(canvas);
|
|
@@ -1728,7 +1948,8 @@ function createRoot(canvas) {
|
|
|
1728
1948
|
performance,
|
|
1729
1949
|
raycaster: raycastOptions,
|
|
1730
1950
|
camera: cameraOptions,
|
|
1731
|
-
onPointerMissed
|
|
1951
|
+
onPointerMissed,
|
|
1952
|
+
stages
|
|
1732
1953
|
} = props;
|
|
1733
1954
|
let state = store.getState(); // Set up renderer (one time only!)
|
|
1734
1955
|
|
|
@@ -1819,14 +2040,8 @@ function createRoot(canvas) {
|
|
|
1819
2040
|
if (!isBoolean) Object.assign(gl.shadowMap, shadows);else gl.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
|
|
1820
2041
|
if (old !== gl.shadowMap.enabled) gl.shadowMap.needsUpdate = true;
|
|
1821
2042
|
}
|
|
1822
|
-
} //
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
if ('ColorManagement' in THREE__namespace) {
|
|
1827
|
-
setDeep(THREE__namespace, legacy, ['ColorManagement', 'legacyMode']);
|
|
1828
|
-
}
|
|
1829
|
-
|
|
2043
|
+
} // Set color management
|
|
2044
|
+
THREE__namespace.ColorManagement.legacyMode = legacy;
|
|
1830
2045
|
const outputEncoding = linear ? THREE__namespace.LinearEncoding : THREE__namespace.sRGBEncoding;
|
|
1831
2046
|
const toneMapping = flat ? THREE__namespace.NoToneMapping : THREE__namespace.ACESFilmicToneMapping;
|
|
1832
2047
|
if (gl.outputEncoding !== outputEncoding) gl.outputEncoding = outputEncoding;
|
|
@@ -1877,7 +2092,9 @@ function createRoot(canvas) {
|
|
|
1877
2092
|
performance: { ...state.performance,
|
|
1878
2093
|
...performance
|
|
1879
2094
|
}
|
|
1880
|
-
})); //
|
|
2095
|
+
})); // Create update stages.
|
|
2096
|
+
|
|
2097
|
+
if (stages !== state.internal.stages) createStages(stages, store); // Set locals
|
|
1881
2098
|
|
|
1882
2099
|
onCreated = onCreatedCallback;
|
|
1883
2100
|
configured = true;
|
|
@@ -2091,6 +2308,9 @@ const act = React__namespace.unstable_act;
|
|
|
2091
2308
|
|
|
2092
2309
|
exports.Block = Block;
|
|
2093
2310
|
exports.ErrorBoundary = ErrorBoundary;
|
|
2311
|
+
exports.FixedStage = FixedStage;
|
|
2312
|
+
exports.Stage = Stage;
|
|
2313
|
+
exports.Stages = Stages;
|
|
2094
2314
|
exports.act = act;
|
|
2095
2315
|
exports.addAfterEffect = addAfterEffect;
|
|
2096
2316
|
exports.addEffect = addEffect;
|
|
@@ -2117,3 +2337,4 @@ exports.useLoader = useLoader;
|
|
|
2117
2337
|
exports.useMutableCallback = useMutableCallback;
|
|
2118
2338
|
exports.useStore = useStore;
|
|
2119
2339
|
exports.useThree = useThree;
|
|
2340
|
+
exports.useUpdate = useUpdate;
|