@displayxr/inline3d 1.7.0 → 1.8.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 +105 -0
- package/README.md +13 -0
- package/js/inline3d-model.js +17 -1
- package/js/inline3d-splat-perf.js +126 -0
- package/js/inline3d-splat-playcanvas.js +1908 -0
- package/js/inline3d-splat-rig.js +268 -3
- package/js/inline3d-splat-shared.js +269 -0
- package/js/inline3d-splat.js +174 -118
- package/js/inline3d-three.js +43 -9
- package/js/inline3d-viewer.js +27 -41
- package/package.json +8 -2
- package/splat.d.ts +137 -7
- package/three.d.ts +17 -0
package/splat.d.ts
CHANGED
|
@@ -34,6 +34,36 @@ export interface SplatPerfOptions {
|
|
|
34
34
|
lodSplatCount?: number;
|
|
35
35
|
/** Minimum on-screen splat size multiplier (needs `lod`); up to ~5 is often invisible. */
|
|
36
36
|
lodRenderScale?: number;
|
|
37
|
+
/**
|
|
38
|
+
* `engine: 'playcanvas'` only — engine-native knobs, passed straight to `app.scene.gsplat`
|
|
39
|
+
* (and winning over the Spark-knob mapping). `splatBudget` is a global splat count per tile.
|
|
40
|
+
*/
|
|
41
|
+
splatBudget?: number;
|
|
42
|
+
/** `engine: 'playcanvas'` only: cull splats whose quad DIAMETER is under this many px. */
|
|
43
|
+
minPixelSize?: number;
|
|
44
|
+
/** `engine: 'playcanvas'` only: the forward-pass alpha floor (engine default 1/255). */
|
|
45
|
+
alphaClipForward?: number;
|
|
46
|
+
/** `engine: 'playcanvas'` only: the engine's AA compensation, for AA-trained assets. */
|
|
47
|
+
antiAlias?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The PlayCanvas backend's viewer (`engine: 'playcanvas'`): the SceneViewer pose surface without
|
|
52
|
+
* three. Not field-compatible with SceneViewer — see docs/playcanvas-adapter.md.
|
|
53
|
+
*/
|
|
54
|
+
export interface PlayCanvasSplatViewer {
|
|
55
|
+
idleSpin: number;
|
|
56
|
+
readonly is3D: boolean;
|
|
57
|
+
depthOffset: number;
|
|
58
|
+
/** The engine's `AppBase`, once booted. */
|
|
59
|
+
readonly app: unknown;
|
|
60
|
+
fitTo(center: number[], extent: number[]): void;
|
|
61
|
+
setPose(pose?: OrbitPose): void;
|
|
62
|
+
getPose(opts?: { target?: boolean }): Required<OrbitPose>;
|
|
63
|
+
resetPose(): void;
|
|
64
|
+
getSubjectBounds(): SubjectBounds & { front: number; back: number; scale: number };
|
|
65
|
+
setFocus(point: number[] | { x: number; y: number; z: number } | null, opts?: { snap?: boolean; recentre?: boolean }): PlayCanvasSplatViewer;
|
|
66
|
+
getFocus(opts?: { target?: boolean }): { x: number; y: number; z: number };
|
|
37
67
|
}
|
|
38
68
|
|
|
39
69
|
/** Camera intrinsics for ONE eye, in pixels, OpenCV convention. */
|
|
@@ -92,14 +122,26 @@ export interface ResolvedRig {
|
|
|
92
122
|
focalEqMm: number;
|
|
93
123
|
/** The live focus, in the splat's own space. */
|
|
94
124
|
focus: number[];
|
|
125
|
+
/**
|
|
126
|
+
* Which step answered the focus. The order: `caller` › `caller-convergence` › `block` (a
|
|
127
|
+
* considered block focus) › `nearest-clump` (the nearest substantial disparity clump in the
|
|
128
|
+
* central half of the frame — needs the block's or the caller's lens) › `block-cloud-median` (a
|
|
129
|
+
* block focus a converter computed as a whole-cloud median) › `median-disparity` › `default`.
|
|
130
|
+
*/
|
|
95
131
|
focusSource:
|
|
96
132
|
| 'caller'
|
|
97
133
|
| 'caller-convergence'
|
|
98
134
|
| 'block'
|
|
135
|
+
| 'nearest-clump'
|
|
136
|
+
| 'block-cloud-median'
|
|
99
137
|
| 'median-disparity'
|
|
100
138
|
| 'default'
|
|
101
139
|
| 'picked'
|
|
102
140
|
| 'set';
|
|
141
|
+
/** The block's own `focus.source` string (e.g. `'convergence'`, `'cloud-median'`), for diagnostics. */
|
|
142
|
+
blockFocusSource: string | null;
|
|
143
|
+
/** Fraction of the central crop's opacity-weighted mass the winning clump carried (`nearest-clump` only). */
|
|
144
|
+
clumpMassFrac: number | null;
|
|
103
145
|
/** What Space returns to. */
|
|
104
146
|
focusDefault: number[];
|
|
105
147
|
focusDefaultSource: string;
|
|
@@ -112,6 +154,22 @@ export interface ResolvedRig {
|
|
|
112
154
|
}
|
|
113
155
|
|
|
114
156
|
export interface SplatOptions {
|
|
157
|
+
/**
|
|
158
|
+
* Which renderer. `'spark'` (the default) is three.js + Spark. `'playcanvas'` is the PlayCanvas
|
|
159
|
+
* engine (optional peer `playcanvas >=2.22.3 <3`, loaded by dynamic import only when asked):
|
|
160
|
+
* same handle, reads `.sog` / `.ply` / a Streamed-SOG `lod-meta.json`. Anything else throws.
|
|
161
|
+
*/
|
|
162
|
+
engine?: 'spark' | 'playcanvas';
|
|
163
|
+
/**
|
|
164
|
+
* `engine: 'playcanvas'` only: the WebGL context's `preserveDrawingBuffer` (default false) —
|
|
165
|
+
* the knob for the weave's zero-copy read race on large canvases.
|
|
166
|
+
*/
|
|
167
|
+
preserveDrawingBuffer?: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* `engine: 'playcanvas'` only: the `playcanvas` module namespace to use instead of
|
|
170
|
+
* `import('playcanvas')` — for a page that already bundles its own copy.
|
|
171
|
+
*/
|
|
172
|
+
playcanvas?: unknown;
|
|
115
173
|
/** Metres of world the tile's height spans (default 0.24). */
|
|
116
174
|
virtualDisplayHeight?: number;
|
|
117
175
|
/**
|
|
@@ -124,7 +182,17 @@ export interface SplatOptions {
|
|
|
124
182
|
flipY?: boolean;
|
|
125
183
|
/** Degrees/second of turntable once idle (default 8). */
|
|
126
184
|
idleSpin?: number;
|
|
185
|
+
/**
|
|
186
|
+
* Drag + wheel. On the PlayCanvas backend the drag is TILT-AND-RELAX: measured as a fraction of
|
|
187
|
+
* the canvas box from the press, it tilts up to ±`orbitMaxDeg` (a half-width swipe reaches it)
|
|
188
|
+
* and relaxes back to rest on release; `idleSpin` resumes once at rest. On Spark (SceneViewer)
|
|
189
|
+
* it is still the cumulative turntable (a full-width drag = 180°).
|
|
190
|
+
*/
|
|
127
191
|
orbit?: boolean;
|
|
192
|
+
/** PlayCanvas: the largest drag tilt, degrees, either axis (default 15). */
|
|
193
|
+
orbitMaxDeg?: number;
|
|
194
|
+
/** PlayCanvas: easing time constants, seconds — `drag` while held (0.2), `rest` after release (0.6). */
|
|
195
|
+
orbitEase?: { drag?: number; rest?: number };
|
|
128
196
|
fit?: 'contain' | 'height' | 'cover' | 'none';
|
|
129
197
|
/** Fraction of the tile the subject may occupy (default 0.8) — width AND height. */
|
|
130
198
|
margin?: number;
|
|
@@ -138,7 +206,11 @@ export interface SplatOptions {
|
|
|
138
206
|
/** Per-eye buffer scale; 0.5–0.7 is usually free (default 1). */
|
|
139
207
|
renderScale?: number;
|
|
140
208
|
feather?: number;
|
|
141
|
-
/**
|
|
209
|
+
/**
|
|
210
|
+
* Spark: minimum ms between splat sorts (default 16, so both eyes share one sort per frame).
|
|
211
|
+
* PlayCanvas: accepted and has no effect — the engine re-sorts when the camera ROTATES, with one
|
|
212
|
+
* directional sort serving every view.
|
|
213
|
+
*/
|
|
142
214
|
sortIntervalMs?: number;
|
|
143
215
|
/**
|
|
144
216
|
* Cut overdraw. UNSET changes nothing — every Spark default stays where Spark put it, so an
|
|
@@ -150,7 +222,7 @@ export interface SplatOptions {
|
|
|
150
222
|
* `true`, −5…−20 % measured) and `'aggressive'` (−22 %) tighten the quad extent instead, which
|
|
151
223
|
* is the axis that actually pays on the web; both move pixels.
|
|
152
224
|
*/
|
|
153
|
-
perf?:
|
|
225
|
+
perf?: boolean | 'exact' | 'balanced' | 'aggressive' | SplatPerfOptions;
|
|
154
226
|
/**
|
|
155
227
|
* Which view rig. `'auto'` (the default) reads it off the ASSET — a `.sog` carrying a `camera`
|
|
156
228
|
* block was lifted from a photograph and gets a camera rig that conserves the recording
|
|
@@ -158,6 +230,14 @@ export interface SplatOptions {
|
|
|
158
230
|
* detectable when `src` is BYTES.
|
|
159
231
|
*/
|
|
160
232
|
rig?: 'auto' | 'display' | 'camera';
|
|
233
|
+
/**
|
|
234
|
+
* Camera rig only: what gives when the canvas is not the capture's shape. `'height'` (default,
|
|
235
|
+
* the 1.7 behaviour) keeps the capture's vertical extent and widens or narrows the horizontal to
|
|
236
|
+
* the canvas. `'cover'` always fills the tile with photograph: a canvas WIDER than the capture
|
|
237
|
+
* keeps the width and crops top/bottom (a 4:3 capture in a 16:9 tile); a narrower one is
|
|
238
|
+
* `'height'`. Both backends; the 3D rig's vertical FOV follows the crop. Anything else throws.
|
|
239
|
+
*/
|
|
240
|
+
captureFit?: 'height' | 'cover';
|
|
161
241
|
/** Camera rig only: the distance in world metres that sits ON the glass. */
|
|
162
242
|
convergence?: number;
|
|
163
243
|
/**
|
|
@@ -191,11 +271,38 @@ export interface SplatOptions {
|
|
|
191
271
|
|
|
192
272
|
/** What {@link addSplat} returns: a TileHandle plus the objects behind it. */
|
|
193
273
|
export interface SplatHandle {
|
|
194
|
-
|
|
195
|
-
|
|
274
|
+
/**
|
|
275
|
+
* SceneViewer on Spark; the PlayCanvas backend's own viewer on `engine: 'playcanvas'` (null
|
|
276
|
+
* there until the backend module has loaded — one module fetch after addSplat returns).
|
|
277
|
+
*/
|
|
278
|
+
readonly viewer: SceneViewer | PlayCanvasSplatViewer;
|
|
279
|
+
/**
|
|
280
|
+
* Spark's SplatMesh; on `engine: 'playcanvas'` a `{ numSplats, entity, asset, resource }`
|
|
281
|
+
* record of the engine objects. Null until the asset is loaded.
|
|
282
|
+
*/
|
|
196
283
|
readonly mesh: object;
|
|
197
|
-
/** Spark's SparkRenderer. */
|
|
198
|
-
readonly spark
|
|
284
|
+
/** Spark's SparkRenderer (absent on `engine: 'playcanvas'`). */
|
|
285
|
+
readonly spark?: object;
|
|
286
|
+
/** Which backend is rendering: `'playcanvas'` or `'spark'`; null until it has loaded. */
|
|
287
|
+
readonly backend: 'playcanvas' | 'spark' | null;
|
|
288
|
+
/**
|
|
289
|
+
* ADVANCED — not covered by the semver promise. The renderer objects behind this window, for a
|
|
290
|
+
* page that wants to add its own content. Null until the backend has booted.
|
|
291
|
+
*
|
|
292
|
+
* PlayCanvas: `{ app, root, camera }` — the tile's `pc.AppBase`; the content root entity (the
|
|
293
|
+
* splat's content space — add your own entities under it, e.g. a glTF through the engine's
|
|
294
|
+
* container loader, skinned and animated included); the eye-rig camera entity. `remove()`
|
|
295
|
+
* destroys the app, and everything under `root` with it.
|
|
296
|
+
*
|
|
297
|
+
* Spark: `{ renderer, scene, camera }` — the WebGLRenderer, the scene, and whichever camera draws
|
|
298
|
+
* the current frame.
|
|
299
|
+
*/
|
|
300
|
+
readonly engine:
|
|
301
|
+
| { readonly app: unknown; readonly root: unknown; readonly camera: unknown }
|
|
302
|
+
| { readonly renderer: unknown; readonly scene: unknown; readonly camera: unknown }
|
|
303
|
+
| null;
|
|
304
|
+
/** `engine: 'playcanvas'` only: the live focus, in the splat's own space. */
|
|
305
|
+
getFocus?(opts?: { target?: boolean }): number[] | null;
|
|
199
306
|
/** Bounds actually used for framing; null until `ready` resolves. */
|
|
200
307
|
frame: SubjectBounds | null;
|
|
201
308
|
/**
|
|
@@ -222,7 +329,30 @@ export interface SplatHandle {
|
|
|
222
329
|
point: number[] | { x: number; y: number; z: number } | null,
|
|
223
330
|
opts?: { snap?: boolean },
|
|
224
331
|
): SplatHandle;
|
|
225
|
-
/**
|
|
332
|
+
/**
|
|
333
|
+
* Swap the asset (URL or bytes) in place. PlayCanvas backend only — throws on Spark.
|
|
334
|
+
*
|
|
335
|
+
* The new file loads BEHIND the current one; then the two crossfade over `fadeMs` (0 = a cut)
|
|
336
|
+
* and the old one is released. The rig waterfall re-runs for the new file (rig, lens, focus and
|
|
337
|
+
* frame update; `onFocusChange` fires). The pose (yaw/pitch/zoom/depth) is kept unless
|
|
338
|
+
* `resetPose`. A newer call supersedes an older one still loading. Resolves once the fade has
|
|
339
|
+
* finished; rejects if the new asset cannot be loaded (the current one stays on screen).
|
|
340
|
+
*/
|
|
341
|
+
setSource(
|
|
342
|
+
src: string | Blob | ArrayBuffer | Uint8Array,
|
|
343
|
+
opts?: { fadeMs?: number; resetPose?: boolean },
|
|
344
|
+
): Promise<SplatHandle>;
|
|
345
|
+
/**
|
|
346
|
+
* Called with the live focus (the splat's own space) whenever it moves — easing included — and
|
|
347
|
+
* which waterfall step it came from. PlayCanvas backend; assign any time, even before `ready`.
|
|
348
|
+
*/
|
|
349
|
+
onFocusChange: ((point: number[], info: { focusSource: ResolvedRig['focusSource'] | null }) => void) | null;
|
|
350
|
+
/**
|
|
351
|
+
* What is under a point on the canvas, in the splat's own space — the double-click's pick.
|
|
352
|
+
* PlayCanvas: the nearest gaussian CENTRE to the ray over the FULL centre set (haze under 5 %
|
|
353
|
+
* opacity skipped); on a Streamed SOG, over the chunks currently resident. Spark: its surface
|
|
354
|
+
* raycast, falling back to the nearest centre.
|
|
355
|
+
*/
|
|
226
356
|
pick(clientX: number, clientY: number): number[] | null;
|
|
227
357
|
|
|
228
358
|
/** Close this window and release its GPU resources. */
|
package/three.d.ts
CHANGED
|
@@ -100,6 +100,23 @@ export function cameraRigFromCamera(
|
|
|
100
100
|
opts?: CameraRigOptions,
|
|
101
101
|
): XRViewRigInit;
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The same CAMERA-rig descriptor as {@link cameraRigFromCamera}, from a plain pose instead of a
|
|
105
|
+
* three.js camera — for a renderer that is not three. Agrees with cameraRigFromCamera to the bit
|
|
106
|
+
* for the same pose.
|
|
107
|
+
*/
|
|
108
|
+
export function cameraRigFromPose(
|
|
109
|
+
pose: {
|
|
110
|
+
/** WORLD position. */
|
|
111
|
+
position: { x: number; y: number; z: number };
|
|
112
|
+
/** WORLD orientation quaternion. */
|
|
113
|
+
orientation: { x: number; y: number; z: number; w: number };
|
|
114
|
+
/** FULL vertical angle in DEGREES (three's `camera.fov` convention). */
|
|
115
|
+
fov: number;
|
|
116
|
+
},
|
|
117
|
+
opts?: CameraRigOptions,
|
|
118
|
+
): XRViewRigInit;
|
|
119
|
+
|
|
103
120
|
/**
|
|
104
121
|
* Build a DISPLAY-rig descriptor — the default rig, made explicit and posable: the canvas is a
|
|
105
122
|
* portal onto a virtual display `virtualDisplayHeight` metres tall. Adds what the scalar
|