@expofp/renderer 3.2.5 → 3.27.1
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/README.md +111 -0
- package/dist/Renderer.d.ts +88 -0
- package/dist/Renderer.js +53 -0
- package/dist/controls/CameraControls.d.ts +102 -0
- package/dist/controls/CameraControls.js +239 -0
- package/dist/controls/camera-api.d.ts +206 -0
- package/dist/controls/camera-api.js +181 -0
- package/dist/controls/camera-move.d.ts +13 -0
- package/dist/controls/camera-move.js +18 -0
- package/dist/controls/camera-state.d.ts +40 -0
- package/dist/controls/camera-state.js +65 -0
- package/dist/controls/gestures.d.ts +70 -0
- package/dist/controls/gestures.js +84 -0
- package/dist/controls/handlers/Inertia.d.ts +111 -0
- package/dist/controls/handlers/Inertia.js +215 -0
- package/dist/controls/handlers/Pan.d.ts +23 -0
- package/dist/controls/handlers/Pan.js +32 -0
- package/dist/controls/handlers/Pitch.d.ts +94 -0
- package/dist/controls/handlers/Pitch.js +191 -0
- package/dist/controls/handlers/Roll.d.ts +103 -0
- package/dist/controls/handlers/Roll.js +182 -0
- package/dist/controls/handlers/Zoom.d.ts +15 -0
- package/dist/controls/handlers/Zoom.js +26 -0
- package/dist/controls/index.d.ts +56 -0
- package/dist/controls/index.js +58 -0
- package/dist/controls/zoom-to.d.ts +89 -0
- package/dist/controls/zoom-to.js +91 -0
- package/dist/core/InstanceUniforms.d.ts +93 -0
- package/dist/core/InstanceUniforms.js +266 -0
- package/dist/core/SquareDataTexture.d.ts +277 -0
- package/dist/core/SquareDataTexture.js +476 -0
- package/dist/core/batch/BatchedMesh.d.ts +74 -0
- package/dist/core/batch/BatchedMesh.js +149 -0
- package/dist/core/instanced/FrustumCulling.d.ts +141 -0
- package/dist/core/instanced/FrustumCulling.js +246 -0
- package/dist/core/instanced/InstancedMesh.d.ts +302 -0
- package/dist/core/instanced/InstancedMesh.js +497 -0
- package/dist/core/instanced/Instances.d.ts +119 -0
- package/dist/core/instanced/Instances.js +230 -0
- package/dist/core/instanced/Raycasting.d.ts +118 -0
- package/dist/core/instanced/Raycasting.js +134 -0
- package/dist/core/instanced/instanced-material.d.ts +77 -0
- package/dist/core/instanced/instanced-material.js +224 -0
- package/dist/core/lines/BatchedLines.d.ts +135 -0
- package/dist/core/lines/BatchedLines.js +213 -0
- package/dist/core/lines/FrustumCulling.d.ts +43 -0
- package/dist/core/lines/FrustumCulling.js +85 -0
- package/dist/core/lines/Raycasting.d.ts +44 -0
- package/dist/core/lines/Raycasting.js +91 -0
- package/dist/core/lines/lines-material.d.ts +47 -0
- package/dist/core/lines/lines-material.js +115 -0
- package/dist/core/shader-source.d.ts +50 -0
- package/dist/core/shader-source.js +84 -0
- package/dist/core/text/BatchedText.d.ts +227 -0
- package/dist/core/text/BatchedText.js +467 -0
- package/dist/core/text/MemberTexture.d.ts +90 -0
- package/dist/core/text/MemberTexture.js +194 -0
- package/dist/core/text/Text.d.ts +73 -0
- package/dist/core/text/Text.js +215 -0
- package/dist/core/text/batched-text-material.d.ts +56 -0
- package/dist/core/text/batched-text-material.js +121 -0
- package/dist/core/text/glyph-packing.d.ts +17 -0
- package/dist/core/text/glyph-packing.js +61 -0
- package/dist/core/typed-array.d.ts +16 -0
- package/dist/core/typed-array.js +20 -0
- package/dist/debug/components/DebugPanelProvider.d.ts +20 -0
- package/dist/debug/components/DebugPanelProvider.js +38 -0
- package/dist/debug/components/DebugTools.d.ts +22 -0
- package/dist/debug/components/DebugTools.js +28 -0
- package/dist/debug/components/Gui.d.ts +20 -0
- package/dist/debug/components/Gui.js +32 -0
- package/dist/debug/components/MemoryInfo.d.ts +22 -0
- package/dist/debug/components/MemoryInfo.js +42 -0
- package/dist/debug/components/Panel.d.ts +31 -0
- package/dist/debug/components/Panel.js +98 -0
- package/dist/debug/components/Stats.d.ts +9 -0
- package/dist/debug/components/Stats.js +24 -0
- package/dist/debug/debug-context.d.ts +41 -0
- package/dist/debug/debug-context.js +59 -0
- package/dist/debug/index.d.ts +51 -0
- package/dist/debug/index.js +64 -0
- package/dist/events/LayoutDriver.d.ts +31 -0
- package/dist/events/LayoutDriver.js +88 -0
- package/dist/events/PointerMissed.d.ts +23 -0
- package/dist/events/PointerMissed.js +58 -0
- package/dist/events/def-culling.d.ts +46 -0
- package/dist/events/def-culling.js +69 -0
- package/dist/events/layout-targets.d.ts +104 -0
- package/dist/events/layout-targets.js +245 -0
- package/dist/events/pointer.d.ts +118 -0
- package/dist/events/pointer.js +168 -0
- package/dist/external/ExternalCanvas.d.ts +56 -0
- package/dist/external/ExternalCanvas.js +178 -0
- package/dist/external/external-camera.d.ts +17 -0
- package/dist/external/external-camera.js +82 -0
- package/dist/external/external-events.d.ts +14 -0
- package/dist/external/external-events.js +33 -0
- package/dist/index.d.ts +11 -783
- package/dist/index.js +12 -8031
- package/dist/objects/Background.d.ts +31 -0
- package/dist/objects/Background.js +37 -0
- package/dist/objects/Lighting.d.ts +20 -0
- package/dist/objects/Lighting.js +85 -0
- package/dist/objects/containers/SlotContainer.d.ts +266 -0
- package/dist/objects/containers/SlotContainer.js +251 -0
- package/dist/objects/containers/hooks.d.ts +46 -0
- package/dist/objects/containers/hooks.js +118 -0
- package/dist/objects/containers/index.d.ts +6 -0
- package/dist/objects/containers/index.js +4 -0
- package/dist/objects/containers/keys.d.ts +10 -0
- package/dist/objects/containers/keys.js +18 -0
- package/dist/objects/containers/mesh-writes.d.ts +106 -0
- package/dist/objects/containers/mesh-writes.js +97 -0
- package/dist/objects/containers/props.d.ts +23 -0
- package/dist/objects/containers/props.js +1 -0
- package/dist/objects/images/ImageInstance.d.ts +29 -0
- package/dist/objects/images/ImageInstance.js +83 -0
- package/dist/objects/images/Images.d.ts +37 -0
- package/dist/objects/images/Images.js +204 -0
- package/dist/objects/images/atlas-packer.d.ts +128 -0
- package/dist/objects/images/atlas-packer.js +315 -0
- package/dist/objects/images/image-container.d.ts +51 -0
- package/dist/objects/images/image-container.js +70 -0
- package/dist/objects/images/index.d.ts +2 -0
- package/dist/objects/images/index.js +1 -0
- package/dist/objects/images/texture-budget.d.ts +120 -0
- package/dist/objects/images/texture-budget.js +215 -0
- package/dist/objects/layer/Layer.d.ts +27 -0
- package/dist/objects/layer/Layer.js +114 -0
- package/dist/objects/layer/index.d.ts +2 -0
- package/dist/objects/layer/index.js +1 -0
- package/dist/objects/layer/mount-scheduler.d.ts +102 -0
- package/dist/objects/layer/mount-scheduler.js +145 -0
- package/dist/objects/layer/visibility-gui.d.ts +19 -0
- package/dist/objects/layer/visibility-gui.js +93 -0
- package/dist/objects/lines/LineInstance.d.ts +21 -0
- package/dist/objects/lines/LineInstance.js +73 -0
- package/dist/objects/lines/Lines.d.ts +17 -0
- package/dist/objects/lines/Lines.js +29 -0
- package/dist/objects/lines/index.d.ts +2 -0
- package/dist/objects/lines/index.js +1 -0
- package/dist/objects/lines/line-container.d.ts +35 -0
- package/dist/objects/lines/line-container.js +40 -0
- package/dist/objects/materials/ColorMaterial.d.ts +85 -0
- package/dist/objects/materials/ColorMaterial.js +89 -0
- package/dist/objects/materials/LineMaterial.d.ts +44 -0
- package/dist/objects/materials/LineMaterial.js +72 -0
- package/dist/objects/materials/ModelMaterial.d.ts +41 -0
- package/dist/objects/materials/ModelMaterial.js +84 -0
- package/dist/objects/materials/TextureMaterial.d.ts +30 -0
- package/dist/objects/materials/TextureMaterial.js +29 -0
- package/dist/objects/materials/dim.d.ts +123 -0
- package/dist/objects/materials/dim.js +213 -0
- package/dist/objects/materials/shared.d.ts +6 -0
- package/dist/objects/materials/shared.js +51 -0
- package/dist/objects/models/ModelInstance.d.ts +22 -0
- package/dist/objects/models/ModelInstance.js +33 -0
- package/dist/objects/models/Models.d.ts +22 -0
- package/dist/objects/models/Models.js +177 -0
- package/dist/objects/models/gltf-cache.d.ts +17 -0
- package/dist/objects/models/gltf-cache.js +50 -0
- package/dist/objects/models/index.d.ts +2 -0
- package/dist/objects/models/index.js +1 -0
- package/dist/objects/models/model-asset.d.ts +48 -0
- package/dist/objects/models/model-asset.js +77 -0
- package/dist/objects/models/model-container.d.ts +139 -0
- package/dist/objects/models/model-container.js +227 -0
- package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
- package/dist/objects/shapes/ShapeInstance.js +40 -0
- package/dist/objects/shapes/Shapes.d.ts +21 -0
- package/dist/objects/shapes/Shapes.js +120 -0
- package/dist/objects/shapes/index.d.ts +2 -0
- package/dist/objects/shapes/index.js +1 -0
- package/dist/objects/shapes/shape-container.d.ts +165 -0
- package/dist/objects/shapes/shape-container.js +272 -0
- package/dist/objects/shapes/shape-geometry.d.ts +27 -0
- package/dist/objects/shapes/shape-geometry.js +94 -0
- package/dist/objects/text/TextInstance.d.ts +22 -0
- package/dist/objects/text/TextInstance.js +95 -0
- package/dist/objects/text/Texts.d.ts +30 -0
- package/dist/objects/text/Texts.js +41 -0
- package/dist/objects/text/index.d.ts +2 -0
- package/dist/objects/text/index.js +1 -0
- package/dist/objects/text/text-container.d.ts +105 -0
- package/dist/objects/text/text-container.js +206 -0
- package/dist/objects/text/text-layout.d.ts +83 -0
- package/dist/objects/text/text-layout.js +154 -0
- package/dist/space/Camera.d.ts +103 -0
- package/dist/space/Camera.js +321 -0
- package/dist/space/Scene.d.ts +44 -0
- package/dist/space/Scene.js +112 -0
- package/dist/space/Space.d.ts +288 -0
- package/dist/space/Space.js +329 -0
- package/dist/space/VisibleRect.d.ts +72 -0
- package/dist/space/VisibleRect.js +129 -0
- package/dist/space/camera-handle.d.ts +67 -0
- package/dist/space/camera-handle.js +63 -0
- package/dist/space/camera-kind.d.ts +26 -0
- package/dist/space/camera-kind.js +30 -0
- package/dist/space/canvas-size.d.ts +24 -0
- package/dist/space/canvas-size.js +20 -0
- package/dist/space/clipping.d.ts +55 -0
- package/dist/space/clipping.js +108 -0
- package/dist/space/layout-measure.d.ts +65 -0
- package/dist/space/layout-measure.js +173 -0
- package/dist/space/viewport.d.ts +112 -0
- package/dist/space/viewport.js +67 -0
- package/dist/types/defs.d.ts +169 -0
- package/dist/types/defs.js +1 -0
- package/dist/types/events.d.ts +183 -0
- package/dist/types/events.js +1 -0
- package/dist/types/guards.d.ts +14 -0
- package/dist/types/guards.js +42 -0
- package/dist/update/index.d.ts +3 -0
- package/dist/update/index.js +2 -0
- package/dist/update/slot-writers.d.ts +30 -0
- package/dist/update/slot-writers.js +72 -0
- package/dist/update/store.d.ts +41 -0
- package/dist/update/store.js +98 -0
- package/dist/utils/arrays.d.ts +13 -0
- package/dist/utils/arrays.js +20 -0
- package/dist/utils/colors.d.ts +19 -0
- package/dist/utils/colors.js +27 -0
- package/dist/utils/logging.d.ts +26 -0
- package/dist/utils/logging.js +47 -0
- package/dist/utils/math.d.ts +24 -0
- package/dist/utils/math.js +27 -0
- package/package.json +67 -19
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { _roots, advance, createRoot, extend } from '@react-three/fiber';
|
|
3
|
+
import { StrictMode, useEffect, useEffectEvent, useRef } from 'react';
|
|
4
|
+
import * as THREE from 'three';
|
|
5
|
+
import { Camera, WebGLRenderer } from 'three';
|
|
6
|
+
import { createLogger } from '../utils/logging';
|
|
7
|
+
import { setExternalCameraProjection } from './external-camera';
|
|
8
|
+
import { externalEvents } from './external-events';
|
|
9
|
+
const logger = createLogger('external');
|
|
10
|
+
/**
|
|
11
|
+
* `<Canvas>`'s stand-in for a host that already owns the canvas: everything the Canvas component
|
|
12
|
+
* does — boot an R3F root, configure the renderer, the events, the size — minus the one thing it
|
|
13
|
+
* cannot share, creating the canvas element. It knows nothing of the scene: `children` render into
|
|
14
|
+
* the root verbatim, so `Renderer` composes one tree and only the mount differs.
|
|
15
|
+
*
|
|
16
|
+
* The bootstrap is imperative because the host's contract is: there is no React tree to mount into
|
|
17
|
+
* until a context exists. R3F's `<Canvas>` cannot serve here — it creates and owns its own canvas
|
|
18
|
+
* element inside a wrapper it renders, and has no way to adopt a foreign one — so this takes R3F's
|
|
19
|
+
* own escape hatch for exactly that, `createRoot(canvas)`, which is all `<Canvas>` wraps anyway.
|
|
20
|
+
* It is configured once per context, while the tree re-renders through props like any other.
|
|
21
|
+
*
|
|
22
|
+
* The camera half is the mount's as well, because the host owns it: one bare camera carries
|
|
23
|
+
* whatever matrix the host handed the frame hook, decomposed into a rigid view and a projection so
|
|
24
|
+
* that everything reading a camera's transform — culling, raycasts, lighting — works unchanged.
|
|
25
|
+
* There is no viewbox fit, no controls and no camera commands; the tree above simply mounts none
|
|
26
|
+
* of them.
|
|
27
|
+
*
|
|
28
|
+
* The demand loop inverts. R3F's own `invalidate` is a no-op under `frameloop: 'never'`, so the
|
|
29
|
+
* store's copy is replaced with the host's `requestFrame` — and every host frame redraws in full,
|
|
30
|
+
* as a shared canvas requires, starting from `resetState()` so three's GL-state tracking never
|
|
31
|
+
* trusts what the host's own drawing left behind.
|
|
32
|
+
* @param props - The host's hooks, and the tree to render into the root.
|
|
33
|
+
* @returns Nothing; the tree renders on the host's canvas, not in this one.
|
|
34
|
+
*/
|
|
35
|
+
export function ExternalCanvas(props) {
|
|
36
|
+
const { gl, requestFrame, onFrame, children } = props;
|
|
37
|
+
// A ref rather than state: nothing renders from the root — the tree renders *into* it — and the
|
|
38
|
+
// forwarding effect always runs after this one within a commit, so it never reads it stale.
|
|
39
|
+
const mountedRef = useRef(undefined);
|
|
40
|
+
// Effect events, so the host handing over a fresh function identity neither re-bootstraps the
|
|
41
|
+
// root nor goes stale: the bootstrap captures these two, and they read the latest props.
|
|
42
|
+
const askFrame = useEffectEvent(() => requestFrame());
|
|
43
|
+
const subscribeFrames = useEffectEvent((draw) => onFrame(draw));
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const external = mountExternal(gl, askFrame, subscribeFrames);
|
|
46
|
+
mountedRef.current = external;
|
|
47
|
+
return () => {
|
|
48
|
+
mountedRef.current = undefined;
|
|
49
|
+
external?.dispose();
|
|
50
|
+
};
|
|
51
|
+
}, [gl]);
|
|
52
|
+
// The tree flows into the foreign root exactly as it would into a Canvas: every children change
|
|
53
|
+
// re-renders it, and only a context change re-bootstraps — `gl` is a dependency here for exactly
|
|
54
|
+
// that case, so a fresh root receives the tree the moment it exists.
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
mountedRef.current?.render(_jsx(StrictMode, { children: children }));
|
|
57
|
+
}, [gl, children]);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Boots an R3F root on the host's canvas and wires it to the host's frame loop.
|
|
62
|
+
* @param context - The host's WebGL context.
|
|
63
|
+
* @param requestFrame - Asks the host for a frame.
|
|
64
|
+
* @param onFrame - Subscribes the per-frame draw to the host.
|
|
65
|
+
* @returns The root and its teardown, or `undefined` when the context has no usable canvas.
|
|
66
|
+
*/
|
|
67
|
+
function mountExternal(context, requestFrame, onFrame) {
|
|
68
|
+
const canvas = context.canvas;
|
|
69
|
+
if (!(canvas instanceof HTMLCanvasElement)) {
|
|
70
|
+
logger.warn('external mode needs a context bound to an HTMLCanvasElement');
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
// `<Canvas>` extends R3F's element catalog with the whole THREE namespace itself; a manual root
|
|
74
|
+
// has to do the same. Idempotent, and the namespace is a module the renderer already ships. The
|
|
75
|
+
// cast steps past the catalog's constructors-only typing — the namespace carries plain values
|
|
76
|
+
// too, which `extend` skips at runtime, exactly as the Canvas path relies on.
|
|
77
|
+
extend(THREE);
|
|
78
|
+
// Deliberately a bare camera: three's frustum cameras derive their projection, and this one's
|
|
79
|
+
// arrives whole from the host each frame. Marked manual so R3F's resize handling leaves it
|
|
80
|
+
// alone; both auto-updates are off because the decomposition writes every matrix by hand.
|
|
81
|
+
const camera = new Camera();
|
|
82
|
+
camera.matrixAutoUpdate = false;
|
|
83
|
+
camera.matrixWorldAutoUpdate = false;
|
|
84
|
+
camera.manual = true;
|
|
85
|
+
// Constructed bare on purpose: the plan is drawn in three's own defaults — no tonemapping, sRGB
|
|
86
|
+
// output — and anything the renderer would opine on is left unset.
|
|
87
|
+
const glRenderer = new WebGLRenderer({ canvas, context });
|
|
88
|
+
// Never clear: the host's own layers are already on the canvas when this renderer draws.
|
|
89
|
+
glRenderer.autoClear = false;
|
|
90
|
+
// The canvas is the host's, twice over. Three would write the css style along with every resize
|
|
91
|
+
// unless told otherwise each time; and R3F's unmount forces a context loss on the renderer it
|
|
92
|
+
// tears down, which on a shared context would take the host's own drawing with it.
|
|
93
|
+
const applySize = glRenderer.setSize.bind(glRenderer);
|
|
94
|
+
glRenderer.setSize = (width, height) => applySize(width, height, false);
|
|
95
|
+
glRenderer.forceContextLoss = () => undefined;
|
|
96
|
+
const measure = () => {
|
|
97
|
+
const rect = canvas.getBoundingClientRect();
|
|
98
|
+
return { width: rect.width, height: rect.height, top: rect.top, left: rect.left };
|
|
99
|
+
};
|
|
100
|
+
const root = createRoot(canvas);
|
|
101
|
+
let disposed = false;
|
|
102
|
+
let configured = false;
|
|
103
|
+
let pending;
|
|
104
|
+
let unsubscribeFrame;
|
|
105
|
+
let observer;
|
|
106
|
+
void root
|
|
107
|
+
.configure({
|
|
108
|
+
gl: glRenderer,
|
|
109
|
+
// `flat` is not an opinion here but a shield: R3F's first configure force-writes
|
|
110
|
+
// `toneMapping` onto any renderer it is handed — ACES filmic unless flat — and flat is the
|
|
111
|
+
// one value that lands on three's own default, NoToneMapping. Everything else stays as the
|
|
112
|
+
// bare constructor left it.
|
|
113
|
+
flat: true,
|
|
114
|
+
// The cast widens past R3F's frustum-camera union; `manual` above is what keeps R3F's own
|
|
115
|
+
// camera handling off it.
|
|
116
|
+
camera: camera,
|
|
117
|
+
frameloop: 'never',
|
|
118
|
+
events: externalEvents,
|
|
119
|
+
size: measure(),
|
|
120
|
+
dpr: window.devicePixelRatio,
|
|
121
|
+
})
|
|
122
|
+
.then(() => {
|
|
123
|
+
if (disposed)
|
|
124
|
+
return;
|
|
125
|
+
const store = _roots.get(canvas)?.store;
|
|
126
|
+
if (!store)
|
|
127
|
+
return;
|
|
128
|
+
// R3F's invalidate no-ops under `frameloop: 'never'`; the host owns the frames, so demand
|
|
129
|
+
// becomes a repaint request. Replaced after configure, which is what wrote the original.
|
|
130
|
+
store.setState({
|
|
131
|
+
invalidate: () => {
|
|
132
|
+
if (!disposed)
|
|
133
|
+
requestFrame();
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
store.getState().events.connect?.(canvas);
|
|
137
|
+
unsubscribeFrame = onFrame((projectionMatrix) => {
|
|
138
|
+
if (disposed)
|
|
139
|
+
return;
|
|
140
|
+
setExternalCameraProjection(camera, projectionMatrix);
|
|
141
|
+
// Three tracks GL state it did not set; sharing a context means resetting that tracking
|
|
142
|
+
// at the start of every frame, or the host's own state reads as three's.
|
|
143
|
+
glRenderer.resetState();
|
|
144
|
+
advance(performance.now(), true, store.getState());
|
|
145
|
+
});
|
|
146
|
+
// The host resizes its own canvas; the root only has to notice. Watching the element beats a
|
|
147
|
+
// host-specific resize event, and a dpr change reaches the same handler through the resize
|
|
148
|
+
// the host performs for it. Feature-detected for the oldest WebViews the SDK still runs in —
|
|
149
|
+
// without the observer the plan still draws, at the size it mounted at.
|
|
150
|
+
if (typeof ResizeObserver === 'function') {
|
|
151
|
+
observer = new ResizeObserver(() => {
|
|
152
|
+
if (disposed)
|
|
153
|
+
return;
|
|
154
|
+
const next = measure();
|
|
155
|
+
store.getState().setSize(next.width, next.height, next.top, next.left);
|
|
156
|
+
store.getState().setDpr(window.devicePixelRatio);
|
|
157
|
+
});
|
|
158
|
+
observer.observe(canvas);
|
|
159
|
+
}
|
|
160
|
+
configured = true;
|
|
161
|
+
if (pending !== undefined)
|
|
162
|
+
root.render(pending);
|
|
163
|
+
requestFrame();
|
|
164
|
+
});
|
|
165
|
+
return {
|
|
166
|
+
render(node) {
|
|
167
|
+
pending = node;
|
|
168
|
+
if (configured)
|
|
169
|
+
root.render(node);
|
|
170
|
+
},
|
|
171
|
+
dispose() {
|
|
172
|
+
disposed = true;
|
|
173
|
+
observer?.disconnect();
|
|
174
|
+
unsubscribeFrame?.();
|
|
175
|
+
root.unmount();
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Camera } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* Decomposes the host's combined world-to-clip matrix into a rigid view matrix and a projection
|
|
4
|
+
* matrix, publishing all four matrices (and their inverses) on the camera.
|
|
5
|
+
*
|
|
6
|
+
* Ported from the imperative renderer's `ExternalCameraSystem`. The split is not unique — many
|
|
7
|
+
* (P′, V′) pairs multiply to the same M — but the *rigid* split is the one three's `Camera` class
|
|
8
|
+
* assumes for `getWorldDirection`, frustum culling, raycasting and the lighting that reads the
|
|
9
|
+
* camera's world matrix. Any extra scale or skew in M (mercator-unit conversion, say) ends up
|
|
10
|
+
* absorbed into P, where it breaks none of those.
|
|
11
|
+
* @param camera - The external camera to publish onto; `matrixAutoUpdate` and
|
|
12
|
+
* `matrixWorldAutoUpdate` must be off, since everything here is written by hand.
|
|
13
|
+
* @param mainMatrix - The combined matrix mapping world space directly to clip space, sixteen
|
|
14
|
+
* elements column-major.
|
|
15
|
+
*/
|
|
16
|
+
export declare function setExternalCameraProjection(camera: Camera, mainMatrix: ArrayLike<number>): void;
|
|
17
|
+
//# sourceMappingURL=external-camera.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Matrix3, Matrix4, Vector3 } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* Decomposes the host's combined world-to-clip matrix into a rigid view matrix and a projection
|
|
4
|
+
* matrix, publishing all four matrices (and their inverses) on the camera.
|
|
5
|
+
*
|
|
6
|
+
* Ported from the imperative renderer's `ExternalCameraSystem`. The split is not unique — many
|
|
7
|
+
* (P′, V′) pairs multiply to the same M — but the *rigid* split is the one three's `Camera` class
|
|
8
|
+
* assumes for `getWorldDirection`, frustum culling, raycasting and the lighting that reads the
|
|
9
|
+
* camera's world matrix. Any extra scale or skew in M (mercator-unit conversion, say) ends up
|
|
10
|
+
* absorbed into P, where it breaks none of those.
|
|
11
|
+
* @param camera - The external camera to publish onto; `matrixAutoUpdate` and
|
|
12
|
+
* `matrixWorldAutoUpdate` must be off, since everything here is written by hand.
|
|
13
|
+
* @param mainMatrix - The combined matrix mapping world space directly to clip space, sixteen
|
|
14
|
+
* elements column-major.
|
|
15
|
+
*/
|
|
16
|
+
export function setExternalCameraProjection(camera, mainMatrix) {
|
|
17
|
+
const M = _main.fromArray(mainMatrix);
|
|
18
|
+
const e = M.elements; // column-major storage: M[row, col] = e[row + 4 * col]
|
|
19
|
+
// Step 1: camera world position c.
|
|
20
|
+
//
|
|
21
|
+
// A standard perspective projection P has its fourth column equal to (0, 0, ±f, 0), so
|
|
22
|
+
// P · [0; 0; 0; 1] is zero in rows 0, 1, and 3. The view matrix V maps the camera position to
|
|
23
|
+
// view-space origin: V · [c; 1] = [0; 0; 0; 1]. Composing these:
|
|
24
|
+
//
|
|
25
|
+
// M · [c; 1] = P · V · [c; 1] = P · [0; 0; 0; 1] = (0, 0, k, 0)
|
|
26
|
+
//
|
|
27
|
+
// so rows 0, 1, and 3 of M dotted with [c; 1] all equal zero. That is a 3×3 linear system for
|
|
28
|
+
// the three components of c, independent of NDC z conventions (standard OpenGL vs. reverse-z),
|
|
29
|
+
// so it works for both maplibre and a vanilla GL setup.
|
|
30
|
+
_system.set(e[0], e[4], e[8], e[1], e[5], e[9], e[3], e[7], e[11]);
|
|
31
|
+
_position.set(-e[12], -e[13], -e[15]).applyMatrix3(_system.invert());
|
|
32
|
+
// Step 2: view direction in world space.
|
|
33
|
+
//
|
|
34
|
+
// Unproject two world-space points along the central view ray and take their difference. The
|
|
35
|
+
// clip-space z boundaries (±1) are used rather than an interior NDC z because maplibre's
|
|
36
|
+
// projection has an infinite far plane in a reverse-z arrangement: an interior z (0 in
|
|
37
|
+
// particular) unprojects to a homogeneous direction at infinity and comes back as NaN after the
|
|
38
|
+
// w-divide. z = ±1 always produces finite points, so the subtraction is well-defined.
|
|
39
|
+
//
|
|
40
|
+
// Which of the two is the near plane depends on the projection's z convention — reverse-z under
|
|
41
|
+
// maplibre, standard under vanilla GL — so it is settled by distance to the eye recovered above:
|
|
42
|
+
// the near point is the closer one, and the view looks from it toward the other. (The imperative
|
|
43
|
+
// renderer hardcoded maplibre's ordering; measuring is what makes both conventions work.)
|
|
44
|
+
_mainInverse.copy(M).invert();
|
|
45
|
+
_near.set(0, 0, 1).applyMatrix4(_mainInverse);
|
|
46
|
+
_far.set(0, 0, -1).applyMatrix4(_mainInverse);
|
|
47
|
+
if (_near.distanceToSquared(_position) > _far.distanceToSquared(_position)) {
|
|
48
|
+
_direction.copy(_near).sub(_far).normalize();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
_direction.copy(_far).sub(_near).normalize();
|
|
52
|
+
}
|
|
53
|
+
// Step 3: synthesize a rigid view matrix via look-at.
|
|
54
|
+
//
|
|
55
|
+
// The choice of "up" is arbitrary as long as it is not parallel to the view direction: any
|
|
56
|
+
// non-degenerate choice yields a valid (P′, V′) pair, because P is recomputed from
|
|
57
|
+
// M · matrixWorld at the end. The fallback handles top-down or bottom-up views where world +z
|
|
58
|
+
// aligns with the view ray.
|
|
59
|
+
_up.set(0, 0, 1);
|
|
60
|
+
if (Math.abs(_up.dot(_direction)) > 0.999)
|
|
61
|
+
_up.set(0, 1, 0);
|
|
62
|
+
_target.copy(_position).add(_direction);
|
|
63
|
+
camera.matrixWorld.lookAt(_position, _target, _up);
|
|
64
|
+
camera.matrixWorld.setPosition(_position);
|
|
65
|
+
camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
|
|
66
|
+
// Step 4: derive projection so that P · V = M exactly.
|
|
67
|
+
//
|
|
68
|
+
// P = M · matrixWorld, because matrixWorld = V⁻¹ and therefore P · V = (M · V⁻¹) · V = M. Any
|
|
69
|
+
// scale or skew that did not fit into the rigid V lives in P.
|
|
70
|
+
camera.projectionMatrix.multiplyMatrices(M, camera.matrixWorld);
|
|
71
|
+
camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert();
|
|
72
|
+
}
|
|
73
|
+
// Scratch, reused across calls so a per-frame update allocates nothing.
|
|
74
|
+
const _main = new Matrix4();
|
|
75
|
+
const _mainInverse = new Matrix4();
|
|
76
|
+
const _system = new Matrix3();
|
|
77
|
+
const _position = new Vector3();
|
|
78
|
+
const _near = new Vector3();
|
|
79
|
+
const _far = new Vector3();
|
|
80
|
+
const _direction = new Vector3();
|
|
81
|
+
const _target = new Vector3();
|
|
82
|
+
const _up = new Vector3();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type EventManager, type RootStore } from '@react-three/fiber';
|
|
2
|
+
/**
|
|
3
|
+
* R3F's DOM event manager, aiming its rays through the hosted camera.
|
|
4
|
+
*
|
|
5
|
+
* The default manager computes its ray with three's `setFromCamera`, which refuses a camera that is
|
|
6
|
+
* neither perspective nor orthographic — and the external camera is deliberately neither, one folded
|
|
7
|
+
* matrix with no transform of its own. Only the computation changes: hit testing, hover tracking,
|
|
8
|
+
* capture and the missed-click path all stay R3F's, so picking under a host behaves exactly as it
|
|
9
|
+
* does under the renderer's own canvas.
|
|
10
|
+
* @param store - The root the manager serves.
|
|
11
|
+
* @returns The event manager.
|
|
12
|
+
*/
|
|
13
|
+
export declare function externalEvents(store: RootStore): EventManager<HTMLElement>;
|
|
14
|
+
//# sourceMappingURL=external-events.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { events as createDomEvents } from '@react-three/fiber';
|
|
2
|
+
import { castRay } from '../space/Space';
|
|
3
|
+
/**
|
|
4
|
+
* R3F's DOM event manager, aiming its rays through the hosted camera.
|
|
5
|
+
*
|
|
6
|
+
* The default manager computes its ray with three's `setFromCamera`, which refuses a camera that is
|
|
7
|
+
* neither perspective nor orthographic — and the external camera is deliberately neither, one folded
|
|
8
|
+
* matrix with no transform of its own. Only the computation changes: hit testing, hover tracking,
|
|
9
|
+
* capture and the missed-click path all stay R3F's, so picking under a host behaves exactly as it
|
|
10
|
+
* does under the renderer's own canvas.
|
|
11
|
+
* @param store - The root the manager serves.
|
|
12
|
+
* @returns The event manager.
|
|
13
|
+
*/
|
|
14
|
+
export function externalEvents(store) {
|
|
15
|
+
const manager = createDomEvents(store);
|
|
16
|
+
return {
|
|
17
|
+
...manager,
|
|
18
|
+
// The canvas is the host's and carries the host's own pointer handling; listening one element
|
|
19
|
+
// up leaves it alone, while `offsetX` stays canvas-relative — the events still target the
|
|
20
|
+
// canvas, which sits alone in its container.
|
|
21
|
+
connect(target) {
|
|
22
|
+
manager.connect?.(target.parentElement ?? target);
|
|
23
|
+
},
|
|
24
|
+
compute(event, state) {
|
|
25
|
+
state.pointer.set((event.offsetX / state.size.width) * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
26
|
+
// R3F's pointer is a bare Vector2; the set above is what put it in NDC.
|
|
27
|
+
castRay(state.raycaster, state.pointer, state.camera);
|
|
28
|
+
// Screen-space raycasts — a route line answering at its drawn width — read the camera off the
|
|
29
|
+
// raycaster; `setFromCamera` writes it and the general-camera path must too.
|
|
30
|
+
state.raycaster.camera = state.camera;
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|