@displayxr/inline3d 1.40.2 → 1.41.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 +47 -0
- package/cursor-depth.d.ts +50 -9
- package/dist/call.js +4 -4
- package/js/camera/pair-cursor.js +94 -69
- package/js/inline3d-cursor-depth-playcanvas.js +21 -17
- package/js/inline3d-cursor-depth.js +183 -61
- package/js/inline3d-three.js +26 -18
- package/model.d.ts +6 -4
- package/package.json +1 -1
- package/splat.d.ts +6 -4
- package/three.d.ts +11 -8
package/js/camera/pair-cursor.js
CHANGED
|
@@ -7,47 +7,45 @@
|
|
|
7
7
|
// two halves ARE the depth: this is ADR-046 Phase 3b done in the page. Block-match a cursor-sized
|
|
8
8
|
// footprint between the eyes and take the nearest confident match.
|
|
9
9
|
//
|
|
10
|
-
// The
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
10
|
+
// The policy is the one every DisplayXR depth cursor follows (runtime ADR-046 Amendment 2), taken
|
|
11
|
+
// from the shared core (../inline3d-cursor-depth.js), not re-implemented here:
|
|
12
|
+
// - never behind the glass: only content that comes OUT of the screen moves it, to the margin
|
|
13
|
+
// (0.03 eye baselines, ~2 mm) in front of that content (cursorTarget);
|
|
14
|
+
// - on the plane it IS the OS cursor: the arrow is drawn into both halves only while the filtered
|
|
15
|
+
// disparity is past the draw threshold (-0.005 baselines, and >= 0.5 px; cursorShouldDraw), the
|
|
16
|
+
// OS cursor hidden exactly then;
|
|
17
|
+
// - the same filter (fast rise, slow sink) and the same arrow (CURSOR_ARROW, tip = hotspot, the
|
|
18
|
+
// OS arrow's 19 CSS px).
|
|
19
|
+
// What is specific to a pair: it has no 3D views, so it works in tile PIXEL disparity — OUTPUT
|
|
20
|
+
// pixels of one eye of the woven buffer, + = crossed (in front of the glass), the sign the rest of
|
|
21
|
+
// camera/ uses — and converts to the core's eye-baseline units through the panel's pixel pitch:
|
|
22
|
+
// buffer px per metre = outW / tileCssWidth / metersPerCssPx (the tile handle's displayMetrics()),
|
|
23
|
+
// times the eye separation (displayMetrics' default, 63 mm). Loaded only when a page asks for
|
|
19
24
|
// `cursor: 'depth'` — zero cost otherwise.
|
|
20
25
|
|
|
21
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
CursorPointer,
|
|
28
|
+
cursorArrowFootprint,
|
|
29
|
+
cursorArrowInset,
|
|
30
|
+
cursorDefaultHeight,
|
|
31
|
+
cursorFilterStep,
|
|
32
|
+
cursorShouldDraw,
|
|
33
|
+
cursorTarget,
|
|
34
|
+
CURSOR_ARROW,
|
|
35
|
+
CURSOR_ARROW_CSS_PX,
|
|
36
|
+
CURSOR_DEFAULT_TUNING,
|
|
37
|
+
} from '../inline3d-cursor-depth.js';
|
|
38
|
+
import { DISPLAY_METRICS_DEFAULTS } from '../inline3d-display-metrics.js';
|
|
22
39
|
import { matchBlock, MIN_NCC } from './disparity.js';
|
|
23
40
|
|
|
24
|
-
/** The arrow's height in CSS px — the OS arrow's apparent size
|
|
25
|
-
export const PAIR_CURSOR_CSS_PX =
|
|
41
|
+
/** The arrow's height in CSS px — the OS arrow's apparent size (the core's CURSOR_ARROW_CSS_PX). */
|
|
42
|
+
export const PAIR_CURSOR_CSS_PX = CURSOR_ARROW_CSS_PX;
|
|
26
43
|
/** Arrow height as a fraction of the tile height when the tile's on-page size is unknown. */
|
|
27
44
|
export const PAIR_CURSOR_HEIGHT = 0.06;
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
* baseline, the runtime's rule) the drawn arrow hands back to the OS cursor. Never under 0.5 px.
|
|
31
|
-
*/
|
|
32
|
-
export const PAIR_CURSOR_SHOW_M = 0.0003;
|
|
33
|
-
export const PAIR_CURSOR_SHOW_MIN_PX = 0.5;
|
|
34
|
-
/**
|
|
35
|
-
* The standard pointer arrow, hotspot at the tip (0, 0), unit = its height, x right, y down: the
|
|
36
|
-
* OS arrow's outline (a 19-px-tall Windows/macOS arrow, normalised).
|
|
37
|
-
*/
|
|
38
|
-
export const PAIR_CURSOR_ARROW = Object.freeze([
|
|
39
|
-
[0, 0], [0, 16 / 19], [4.2 / 19, 12.4 / 19], [6.9 / 19, 18.6 / 19], [9.5 / 19, 17.5 / 19], [6.8 / 19, 11.5 / 19], [11.7 / 19, 11.5 / 19],
|
|
40
|
-
]);
|
|
41
|
-
/**
|
|
42
|
-
* How far in front of out-of-screen content the arrow floats: 2 mm of on-screen disparity — the
|
|
43
|
-
* runtime's 0.03 of the eye baseline (ADR-046 / runtime #1908), so a lifted tile's cursor and a
|
|
44
|
-
* stereo tile's sit the same way. Converted to buffer px through the tile's `displayMetrics()`.
|
|
45
|
-
*/
|
|
46
|
-
export const PAIR_CURSOR_MARGIN_M = 0.002;
|
|
45
|
+
/** The arrow every DisplayXR depth cursor draws (the core's CURSOR_ARROW): tip at (0, 0), unit = its height, y down. */
|
|
46
|
+
export const PAIR_CURSOR_ARROW = CURSOR_ARROW;
|
|
47
47
|
/** One CSS px in metres when the panel cannot say (the CSS reference pixel, 1/96 in). */
|
|
48
48
|
export const PAIR_CURSOR_CSS_PX_M = 0.0254 / 96;
|
|
49
|
-
/** Comfort cap on how far in front the arrow comes, as a fraction of the eye width. */
|
|
50
|
-
export const PAIR_CURSOR_CLAMP = 0.08;
|
|
51
49
|
|
|
52
50
|
/**
|
|
53
51
|
* The displayed disparity of the nearest content under the cursor's footprint, or null when no
|
|
@@ -75,8 +73,8 @@ export function pairFootprintDisparity(luma, geo, u, v, height, aspect) {
|
|
|
75
73
|
const { rL, rR } = geo;
|
|
76
74
|
const k = geo.outW / rL.sw; // output px per source px
|
|
77
75
|
let best = null;
|
|
78
|
-
// The ring
|
|
79
|
-
for (const [pu, pv] of
|
|
76
|
+
// The tip, then a ring centred on the arrow's body: that is what content must not overlap.
|
|
77
|
+
for (const [pu, pv] of cursorArrowFootprint(u, v, height, aspect)) {
|
|
80
78
|
if (!(pu >= 0 && pu <= 1 && pv >= 0 && pv <= 1)) continue;
|
|
81
79
|
const su = geo.mirror ? 1 - pu : pu;
|
|
82
80
|
const x = Math.round((rL.sx + su * rL.sw) * scale - b / 2);
|
|
@@ -91,49 +89,69 @@ export function pairFootprintDisparity(luma, geo, u, v, height, aspect) {
|
|
|
91
89
|
return best;
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
/**
|
|
95
|
-
* The arrow's target disparity: in front of content that comes OUT of the screen (its disparity
|
|
96
|
-
* plus the margin, clamped), else the glass. Never behind the glass — the cursor does not go inside
|
|
97
|
-
* the display.
|
|
98
|
-
* @param {number} marginPx the margin in output px (pairCursorScale × PAIR_CURSOR_MARGIN_M)
|
|
99
|
-
*/
|
|
100
|
-
export function pairCursorTarget(contentPx, outW, marginPx) {
|
|
101
|
-
if (contentPx === null || !Number.isFinite(contentPx) || !(contentPx > 0)) return 0;
|
|
102
|
-
return Math.min(PAIR_CURSOR_CLAMP * outW, contentPx + marginPx);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
92
|
/**
|
|
106
93
|
* Output px of one eye per metre on the glass: the buffer eye is stretched over the tile's CSS
|
|
107
|
-
* width, and one CSS px is `metersPerCssPx` on the panel.
|
|
94
|
+
* width, and one CSS px is `metersPerCssPx` on the panel (the CSS reference px when unknown).
|
|
108
95
|
*/
|
|
109
96
|
export function pairCursorScale(outW, tileCssWidth, metersPerCssPx) {
|
|
110
97
|
const m = metersPerCssPx > 0 && Number.isFinite(metersPerCssPx) ? metersPerCssPx : PAIR_CURSOR_CSS_PX_M;
|
|
111
98
|
return tileCssWidth > 0 ? outW / tileCssWidth / m : outW / (1000 * m);
|
|
112
99
|
}
|
|
113
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Output px of on-screen disparity per eye-baseline unit — the conversion between this module's
|
|
103
|
+
* pixels and the core's units: pairCursorScale × the eye separation.
|
|
104
|
+
*/
|
|
105
|
+
export function pairPxPerBaseline(outW, tileCssWidth, metersPerCssPx, eyeSeparationM = DISPLAY_METRICS_DEFAULTS.eyeSeparationM) {
|
|
106
|
+
return pairCursorScale(outW, tileCssWidth, metersPerCssPx) * eyeSeparationM;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The arrow's target disparity in output px (+ = in front): the core's policy (cursorTarget) on
|
|
111
|
+
* the content's disparity, converted through `pxPerBaseline`. In front of content that comes OUT
|
|
112
|
+
* of the screen by the margin (0.03 baselines), else the glass — never behind it.
|
|
113
|
+
*/
|
|
114
|
+
export function pairCursorTarget(contentPx, pxPerBaseline, tuning = CURSOR_DEFAULT_TUNING) {
|
|
115
|
+
if (contentPx === null || !Number.isFinite(contentPx) || !(pxPerBaseline > 0)) return 0;
|
|
116
|
+
return -cursorTarget(tuning, true, -contentPx / pxPerBaseline) * pxPerBaseline || 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** The arrow's fill, inset by one output px (at least 1/19 of its height), cached per size. */
|
|
120
|
+
const _fillBySize = new Map();
|
|
121
|
+
function arrowFill(sizePx) {
|
|
122
|
+
const d = sizePx > 0 ? Math.max(1 / 19, 1 / sizePx) : 1 / 19;
|
|
123
|
+
const key = Math.round(d * 1e4);
|
|
124
|
+
let f = _fillBySize.get(key);
|
|
125
|
+
if (!f) {
|
|
126
|
+
if (_fillBySize.size > 32) _fillBySize.clear();
|
|
127
|
+
_fillBySize.set(key, (f = cursorArrowInset(d)));
|
|
128
|
+
}
|
|
129
|
+
return f;
|
|
130
|
+
}
|
|
131
|
+
|
|
114
132
|
/**
|
|
115
133
|
* Draw the arrow into both halves of a woven buffer: the left eye's copy `disparityPx / 2` right of
|
|
116
|
-
* the pointer, the right eye's as far left (crossed = in front).
|
|
117
|
-
*
|
|
134
|
+
* the pointer, the right eye's as far left (crossed = in front). The shared arrow: its dark outline
|
|
135
|
+
* polygon, then the white fill inset by a px; the tip on the hotspot. Each copy is clipped to its
|
|
136
|
+
* own half, so an arrow at the edge never bleeds into the other eye.
|
|
118
137
|
* @param {number} sizePx arrow height in output px
|
|
119
138
|
*/
|
|
120
139
|
export function drawPairArrow(g, outW, outH, u, v, disparityPx, sizePx) {
|
|
121
140
|
const cy = v * outH;
|
|
141
|
+
const fill = arrowFill(sizePx);
|
|
122
142
|
for (const eye of [0, 1]) {
|
|
123
143
|
const cx = eye * outW + u * outW + (eye === 0 ? disparityPx / 2 : -disparityPx / 2);
|
|
124
144
|
g.save();
|
|
125
145
|
g.beginPath();
|
|
126
146
|
g.rect(eye * outW, 0, outW, outH);
|
|
127
147
|
g.clip();
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
g.strokeStyle = '#000';
|
|
136
|
-
g.stroke();
|
|
148
|
+
for (const [poly, style] of [[CURSOR_ARROW, '#000'], [fill, '#fff']]) {
|
|
149
|
+
g.beginPath();
|
|
150
|
+
poly.forEach(([x, y], k) => (k ? g.lineTo : g.moveTo).call(g, cx + x * sizePx, cy + y * sizePx));
|
|
151
|
+
g.closePath();
|
|
152
|
+
g.fillStyle = style;
|
|
153
|
+
g.fill();
|
|
154
|
+
}
|
|
137
155
|
g.restore();
|
|
138
156
|
}
|
|
139
157
|
}
|
|
@@ -156,7 +174,9 @@ export class PairCursor {
|
|
|
156
174
|
this._metricsFor = null; // the tile handle whose displayMetrics() was asked for
|
|
157
175
|
/** One CSS px on the panel, metres, once the tile's handle has said (else the CSS reference px). */
|
|
158
176
|
this.metersPerCssPx = null;
|
|
159
|
-
/** The
|
|
177
|
+
/** The eye separation (metres) the baseline units convert with: displayMetrics' (a default today). */
|
|
178
|
+
this.eyeSeparationM = DISPLAY_METRICS_DEFAULTS.eyeSeparationM;
|
|
179
|
+
/** The last frame's placement, for diagnostics: `{ contentPx, targetPx, disparityPx, filteredPx, drawn, pxPerBaseline }` (output px, + = in front) or null. */
|
|
160
180
|
this.last = null;
|
|
161
181
|
}
|
|
162
182
|
|
|
@@ -186,14 +206,16 @@ export class PairCursor {
|
|
|
186
206
|
}
|
|
187
207
|
this._askMetrics(geo.handle);
|
|
188
208
|
const r = this.pointer.canvas.getBoundingClientRect?.();
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
const
|
|
209
|
+
const pxPerBaseline = pairPxPerBaseline(geo.outW, r && r.width, this.metersPerCssPx, this.eyeSeparationM);
|
|
210
|
+
// The core's policy and filter, in its units (eye baselines, < 0 = in front).
|
|
211
|
+
const content = this._content === null ? null : -this._content / pxPerBaseline;
|
|
212
|
+
const target = cursorTarget(CURSOR_DEFAULT_TUNING, content !== null, content);
|
|
213
|
+
const d = cursorFilterStep(this.filter, CURSOR_DEFAULT_TUNING, target, nowSec);
|
|
214
|
+
const drawn = cursorShouldDraw(d, pxPerBaseline);
|
|
215
|
+
const disparity = -d * pxPerBaseline; // output px, + = in front
|
|
194
216
|
if (drawn) drawPairArrow(g, geo.outW, geo.outH, u, v, disparity, hf * geo.outH);
|
|
195
217
|
this.pointer.hideCss(drawn); // the OS arrow IS the cursor on the plane
|
|
196
|
-
this.last = { contentPx: this._content, targetPx: target, disparityPx: drawn ? disparity : 0, drawn };
|
|
218
|
+
this.last = { contentPx: this._content, targetPx: -target * pxPerBaseline || 0, disparityPx: drawn ? disparity : 0, filteredPx: disparity || 0, drawn, pxPerBaseline };
|
|
197
219
|
return this.last;
|
|
198
220
|
}
|
|
199
221
|
|
|
@@ -201,17 +223,20 @@ export class PairCursor {
|
|
|
201
223
|
_askMetrics(handle) {
|
|
202
224
|
if (!handle || handle === this._metricsFor || typeof handle.displayMetrics !== 'function') return;
|
|
203
225
|
this._metricsFor = handle;
|
|
204
|
-
Promise.resolve(
|
|
226
|
+
Promise.resolve()
|
|
227
|
+
.then(() => handle.displayMetrics())
|
|
205
228
|
.then((m) => {
|
|
206
|
-
if (this._metricsFor
|
|
229
|
+
if (this._metricsFor !== handle || !m) return;
|
|
230
|
+
if (m.metersPerCssPx > 0) this.metersPerCssPx = m.metersPerCssPx;
|
|
231
|
+
if (m.eyeSeparationM > 0) this.eyeSeparationM = m.eyeSeparationM;
|
|
207
232
|
})
|
|
208
233
|
.catch(() => {});
|
|
209
234
|
}
|
|
210
235
|
|
|
211
|
-
/** The OS arrow's height as a fraction of the tile's on-page height. */
|
|
236
|
+
/** The OS arrow's height as a fraction of the tile's on-page height (the core's default size). */
|
|
212
237
|
_osArrowFraction() {
|
|
213
238
|
const r = this.pointer.canvas.getBoundingClientRect?.();
|
|
214
|
-
return r && r.height > 0 ?
|
|
239
|
+
return r && r.height > 0 ? cursorDefaultHeight(r.height) : PAIR_CURSOR_HEIGHT;
|
|
215
240
|
}
|
|
216
241
|
|
|
217
242
|
/** Not drawing this frame (pointer away, tile not woven): the CSS cursor comes back. */
|
|
@@ -14,18 +14,20 @@
|
|
|
14
14
|
// runtime's one-frame-late app hint.
|
|
15
15
|
//
|
|
16
16
|
// Placement: the same maths as everywhere else (./inline3d-cursor-depth.js, a port of the
|
|
17
|
-
// runtime's u_cursor_depth, ADR-046), solved in WORLD space from this
|
|
18
|
-
// through the rig node. Drawn
|
|
19
|
-
//
|
|
20
|
-
// UI layer, so
|
|
17
|
+
// runtime's u_cursor_depth, ADR-046 + Amendment 2's policy), solved in WORLD space from this
|
|
18
|
+
// frame's views carried through the rig node. Drawn — only while content under it comes out of the
|
|
19
|
+
// glass — as the classic arrow (the shared cursorArrowMesh: dark outline, white fill, tip on the
|
|
20
|
+
// hotspot) in the UI layer with depth test off, so every eye camera draws it last and nothing
|
|
21
|
+
// occludes it; the picker skips the UI layer, so the cursor never picks itself. On the plane
|
|
22
|
+
// nothing is drawn and the CSS cursor is the cursor.
|
|
21
23
|
|
|
22
24
|
import {
|
|
23
25
|
CursorDepthPlacer,
|
|
24
26
|
CursorPointer,
|
|
25
|
-
CURSOR_DEFAULT_HEIGHT,
|
|
26
27
|
CURSOR_DEFAULT_TUNING,
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
cursorArrowMesh,
|
|
29
|
+
cursorArrowFootprint,
|
|
30
|
+
cursorDefaultHeight,
|
|
29
31
|
cursorViewRay,
|
|
30
32
|
} from './inline3d-cursor-depth.js';
|
|
31
33
|
|
|
@@ -42,10 +44,11 @@ export class PlayCanvasDepthCursor {
|
|
|
42
44
|
* @param {object} viewer the PlayCanvasSplatViewer (app, rigNode, eye are read lazily).
|
|
43
45
|
* @param {{canvas: HTMLElement, height?: number, margin?: number, anchor?: string, pointerScope?: string}} opts
|
|
44
46
|
*/
|
|
45
|
-
constructor(pc, viewer, { canvas, height
|
|
47
|
+
constructor(pc, viewer, { canvas, height, margin, anchor = 'hybrid', pointerScope = 'canvas' }) {
|
|
46
48
|
this.pc = pc;
|
|
47
49
|
this.viewer = viewer;
|
|
48
|
-
|
|
50
|
+
/** Sprite height (canvas heights) when set; null = the OS arrow's size, from the canvas's on-page height. */
|
|
51
|
+
this.height = height > 0 && Number.isFinite(height) ? height : null;
|
|
49
52
|
this.pointer = new CursorPointer(canvas, { scope: pointerScope });
|
|
50
53
|
const tuning = margin > 0 && Number.isFinite(margin) ? { ...CURSOR_DEFAULT_TUNING, margin } : CURSOR_DEFAULT_TUNING;
|
|
51
54
|
this.placer = new CursorDepthPlacer(tuning, { anchor });
|
|
@@ -89,16 +92,17 @@ export class PlayCanvasDepthCursor {
|
|
|
89
92
|
console.warn('[inline3d] cursor: depth: a PlayCanvas pick did not answer in time; retrying (cursor on the glass meanwhile).');
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
|
-
|
|
95
|
+
const h = this.height ?? cursorDefaultHeight(this.pointer.cssHeight());
|
|
96
|
+
if (this._frame++ % PICK_EVERY === 0 && !this._inFlight) this._pick(app, rig, entries[0], uv, h);
|
|
93
97
|
const now = (globalThis.performance ? globalThis.performance.now() : Date.now()) / 1000;
|
|
94
|
-
const p = this.placer.update(views, { u: uv[0], v: uv[1], nearestPoint: this.hit, cursorHeight: this.
|
|
98
|
+
const p = this.placer.update(views, { u: uv[0], v: uv[1], nearestPoint: this.hit, cursorHeight: h, canvasPx: this.pointer.panelPx() }, now);
|
|
95
99
|
this.placement = p;
|
|
96
100
|
this.pointer.hideCss(!!p.active);
|
|
97
101
|
const sprite = this._sprite || (p.active ? this._makeSprite(app) : null);
|
|
98
102
|
if (!sprite) return;
|
|
99
103
|
sprite.mi.visible = !!p.active;
|
|
100
104
|
if (!p.active) return;
|
|
101
|
-
// The unit
|
|
105
|
+
// The unit arrow in the sprite's XY plane, tip at its origin: basis (rotation), height (scale), position = the hotspot.
|
|
102
106
|
const { x, y, z } = p.basis;
|
|
103
107
|
const q = quatFromMatrix([x[0], x[1], x[2], 0, y[0], y[1], y[2], 0, z[0], z[1], z[2], 0, 0, 0, 0, 1]);
|
|
104
108
|
sprite.node.setLocalPosition(p.position[0], p.position[1], p.position[2]);
|
|
@@ -114,11 +118,11 @@ export class PlayCanvasDepthCursor {
|
|
|
114
118
|
this.pointer.hideCss(false);
|
|
115
119
|
}
|
|
116
120
|
|
|
117
|
-
// The
|
|
118
|
-
//
|
|
121
|
+
// The arrow: one mesh (outline triangles first, fill after — the order a depth-test-off draw
|
|
122
|
+
// needs), vertex-coloured, alpha-blended, in the UI layer.
|
|
119
123
|
_makeSprite(app) {
|
|
120
124
|
const pc = this.pc;
|
|
121
|
-
const m =
|
|
125
|
+
const m = cursorArrowMesh();
|
|
122
126
|
const mesh = new pc.Mesh(app.graphicsDevice);
|
|
123
127
|
mesh.setPositions(m.positions);
|
|
124
128
|
mesh.setColors(m.colors);
|
|
@@ -179,7 +183,7 @@ export class PlayCanvasDepthCursor {
|
|
|
179
183
|
}
|
|
180
184
|
|
|
181
185
|
// Render the pick buffer from the first eye and read the footprint's world points.
|
|
182
|
-
_pick(app, rig, e, uv) {
|
|
186
|
+
_pick(app, rig, e, uv, height) {
|
|
183
187
|
const pc = this.pc;
|
|
184
188
|
const aspect = e.width > 0 && e.height > 0 ? e.width / e.height : 1;
|
|
185
189
|
const W = PICK_WIDTH;
|
|
@@ -240,7 +244,7 @@ export class PlayCanvasDepthCursor {
|
|
|
240
244
|
const Mw = view.transformMatrix;
|
|
241
245
|
const f = [-Mw[8], -Mw[9], -Mw[10]];
|
|
242
246
|
const zNear = cam.camera.nearClip, zFar = cam.camera.farClip;
|
|
243
|
-
const samples =
|
|
247
|
+
const samples = cursorArrowFootprint(uv[0], uv[1], height, this.pointer.aspect())
|
|
244
248
|
.filter(([u, v]) => u >= 0 && u <= 1 && v >= 0 && v <= 1)
|
|
245
249
|
.map(([u, v]) =>
|
|
246
250
|
picker.getPointDepthAsync(Math.min(W - 1, Math.floor(u * W)), Math.min(H - 1, Math.floor(v * H))).then((lin) => {
|