three-gamepad-controls 0.25.2 → 0.25.4
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.
|
@@ -9,7 +9,8 @@ import { DragControls } from "three/addons/controls/DragControls.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export type GamepadDragControlsOptions = GamepadControlsOptions & {
|
|
11
11
|
/**
|
|
12
|
-
* Screen-relative translation speed multiplier.
|
|
12
|
+
* Screen-relative translation speed multiplier. At full processed input,
|
|
13
|
+
* `1` moves one effective viewport width or height per second on each axis.
|
|
13
14
|
* @default 1.0
|
|
14
15
|
*/
|
|
15
16
|
dragSpeed: number;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
|
|
2
2
|
import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
|
|
3
3
|
import { GamepadControls } from "./gamepad-controls.js";
|
|
4
|
+
import { getCameraViewSize } from "./three-utils.js";
|
|
4
5
|
import { Matrix4, Vector2, Vector3 } from "three";
|
|
5
6
|
//#region src/gamepad-drag-controls.ts
|
|
6
7
|
const DEFAULT_DRAG_OPTIONS = {
|
|
@@ -32,8 +33,6 @@ var GamepadDragControls = class extends GamepadControls {
|
|
|
32
33
|
#parentInverse;
|
|
33
34
|
#selectedWorldPosition;
|
|
34
35
|
#selectedLocalPosition;
|
|
35
|
-
#cameraWorldPosition;
|
|
36
|
-
#cameraForward;
|
|
37
36
|
#cameraRight;
|
|
38
37
|
#cameraUp;
|
|
39
38
|
#cameraToSelected;
|
|
@@ -59,8 +58,6 @@ var GamepadDragControls = class extends GamepadControls {
|
|
|
59
58
|
this.#parentInverse = new Matrix4();
|
|
60
59
|
this.#selectedWorldPosition = new Vector3();
|
|
61
60
|
this.#selectedLocalPosition = new Vector3();
|
|
62
|
-
this.#cameraWorldPosition = new Vector3();
|
|
63
|
-
this.#cameraForward = new Vector3();
|
|
64
61
|
this.#cameraRight = new Vector3();
|
|
65
62
|
this.#cameraUp = new Vector3();
|
|
66
63
|
this.#cameraToSelected = new Vector3();
|
|
@@ -151,8 +148,7 @@ var GamepadDragControls = class extends GamepadControls {
|
|
|
151
148
|
*/
|
|
152
149
|
#applyDrag(selected, deltaTime, dragX, dragY, dragSpeed) {
|
|
153
150
|
if (dragX === 0 && dragY === 0) return false;
|
|
154
|
-
this.#
|
|
155
|
-
this.#updateViewSizeAtSelectedDepth();
|
|
151
|
+
this.#updateDragCameraState();
|
|
156
152
|
const scale = dragSpeed * deltaTime;
|
|
157
153
|
this.#selectedWorldPosition.addScaledVector(this.#cameraRight, dragX * this.#viewSize.x * scale);
|
|
158
154
|
this.#selectedWorldPosition.addScaledVector(this.#cameraUp, -dragY * this.#viewSize.y * scale);
|
|
@@ -185,6 +181,7 @@ var GamepadDragControls = class extends GamepadControls {
|
|
|
185
181
|
#intersectCenter() {
|
|
186
182
|
const controls = this.#controls;
|
|
187
183
|
this.#intersections.length = 0;
|
|
184
|
+
controls.object.updateWorldMatrix(true, false);
|
|
188
185
|
controls.raycaster.setFromCamera(this.#centerNdc, controls.object);
|
|
189
186
|
controls.raycaster.intersectObjects(controls.objects, controls.recursive, this.#intersections);
|
|
190
187
|
return this.#intersections[0];
|
|
@@ -276,42 +273,17 @@ var GamepadDragControls = class extends GamepadControls {
|
|
|
276
273
|
}
|
|
277
274
|
#updateCameraAxes() {
|
|
278
275
|
const camera = this.#controls.object;
|
|
276
|
+
camera.updateWorldMatrix(true, false);
|
|
279
277
|
this.#cameraRight.set(1, 0, 0).applyQuaternion(camera.quaternion).normalize();
|
|
280
278
|
this.#cameraUp.set(0, 1, 0).applyQuaternion(camera.quaternion).normalize();
|
|
281
|
-
camera.getWorldDirection(this.#cameraForward).normalize();
|
|
282
279
|
}
|
|
283
|
-
#
|
|
280
|
+
#updateDragCameraState() {
|
|
284
281
|
const camera = this.#controls.object;
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
camera.getWorldPosition(this.#cameraWorldPosition);
|
|
291
|
-
const depth = Math.max(Number.EPSILON, this.#cameraToSelected.copy(this.#selectedWorldPosition).sub(this.#cameraWorldPosition).dot(this.#cameraForward));
|
|
292
|
-
const height = 2 * Math.tan(camera.fov * Math.PI / 360) * depth;
|
|
293
|
-
this.#viewSize.set(height * camera.aspect, height);
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
this.#viewSize.set(1, 1);
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Narrows a Three.js camera to `PerspectiveCamera`.
|
|
300
|
-
*
|
|
301
|
-
* @param camera - Camera to inspect.
|
|
302
|
-
* @returns `true` when the camera is perspective.
|
|
303
|
-
*/
|
|
304
|
-
#isPerspectiveCamera(camera) {
|
|
305
|
-
return camera.isPerspectiveCamera === true;
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Narrows a Three.js camera to `OrthographicCamera`.
|
|
309
|
-
*
|
|
310
|
-
* @param camera - Camera to inspect.
|
|
311
|
-
* @returns `true` when the camera is orthographic.
|
|
312
|
-
*/
|
|
313
|
-
#isOrthographicCamera(camera) {
|
|
314
|
-
return camera.isOrthographicCamera === true;
|
|
282
|
+
camera.updateWorldMatrix(true, false);
|
|
283
|
+
const view = camera.matrixWorldInverse.elements;
|
|
284
|
+
this.#cameraRight.set(view[0], view[4], view[8]).normalize();
|
|
285
|
+
this.#cameraUp.set(view[1], view[5], view[9]).normalize();
|
|
286
|
+
getCameraViewSize(camera, this.#selectedWorldPosition, this.#viewSize, this.#cameraToSelected);
|
|
315
287
|
}
|
|
316
288
|
};
|
|
317
289
|
//#endregion
|
|
@@ -9,7 +9,9 @@ import { TransformControls } from "three/addons/controls/TransformControls.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export type GamepadTransformControlsOptions = GamepadControlsOptions & {
|
|
11
11
|
/**
|
|
12
|
-
* Screen-relative translation speed multiplier.
|
|
12
|
+
* Screen-relative translation speed multiplier. `XYZ` uses effective viewport
|
|
13
|
+
* width and height per second; constrained axes use their mean in world units
|
|
14
|
+
* per second. Both are multiplied by the processed stick input.
|
|
13
15
|
* @default 1.0
|
|
14
16
|
*/
|
|
15
17
|
translateSpeed: number;
|
|
@@ -90,6 +92,8 @@ export type GamepadTransformControlsOptions = GamepadControlsOptions & {
|
|
|
90
92
|
* Modes and axes are selected explicitly with buttons. Moving the transform
|
|
91
93
|
* stick starts a native-style transform interaction, and releasing it ends
|
|
92
94
|
* the interaction while keeping the active axis highlighted.
|
|
95
|
+
* Selection follows the native helper's explicit visibility flags, including
|
|
96
|
+
* combined axes and planes, independently of camera-alignment hiding.
|
|
93
97
|
*/
|
|
94
98
|
export declare class GamepadTransformControls extends GamepadControls {
|
|
95
99
|
#private;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
|
|
2
2
|
import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
|
|
3
3
|
import { GamepadControls } from "./gamepad-controls.js";
|
|
4
|
+
import { getCameraViewSize } from "./three-utils.js";
|
|
4
5
|
import { Matrix4, Quaternion, Vector2, Vector3 } from "three";
|
|
5
6
|
//#region src/gamepad-transform-controls.ts
|
|
6
7
|
const DEFAULT_TRANSFORM_OPTIONS = {
|
|
@@ -65,6 +66,8 @@ const PROJECTED_AXIS_EPSILON = .001;
|
|
|
65
66
|
* Modes and axes are selected explicitly with buttons. Moving the transform
|
|
66
67
|
* stick starts a native-style transform interaction, and releasing it ends
|
|
67
68
|
* the interaction while keeping the active axis highlighted.
|
|
69
|
+
* Selection follows the native helper's explicit visibility flags, including
|
|
70
|
+
* combined axes and planes, independently of camera-alignment hiding.
|
|
68
71
|
*/
|
|
69
72
|
var GamepadTransformControls = class extends GamepadControls {
|
|
70
73
|
#controls;
|
|
@@ -73,6 +76,7 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
73
76
|
#viewSize;
|
|
74
77
|
#parentInverse;
|
|
75
78
|
#cameraWorldPosition;
|
|
79
|
+
#cameraSpacePosition;
|
|
76
80
|
#cameraForward;
|
|
77
81
|
#cameraRight;
|
|
78
82
|
#cameraUp;
|
|
@@ -135,6 +139,7 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
135
139
|
this.#viewSize = new Vector2();
|
|
136
140
|
this.#parentInverse = new Matrix4();
|
|
137
141
|
this.#cameraWorldPosition = new Vector3();
|
|
142
|
+
this.#cameraSpacePosition = new Vector3();
|
|
138
143
|
this.#cameraForward = new Vector3();
|
|
139
144
|
this.#cameraRight = new Vector3();
|
|
140
145
|
this.#cameraUp = new Vector3();
|
|
@@ -318,9 +323,10 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
318
323
|
* callbacks, interrupting this update if its context or segment was invalidated.
|
|
319
324
|
*
|
|
320
325
|
* @param context - Context expected after the operation that invoked callbacks.
|
|
326
|
+
* @param validateAxis - Also validate a newly selected axis before acquisition.
|
|
321
327
|
* @returns `true` when this update may continue applying gamepad input.
|
|
322
328
|
*/
|
|
323
|
-
#afterCallback(context) {
|
|
329
|
+
#afterCallback(context, validateAxis = false) {
|
|
324
330
|
const segment = this.#segment;
|
|
325
331
|
if (!this.#matchesContext(context)) {
|
|
326
332
|
this.#interrupted = true;
|
|
@@ -328,6 +334,7 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
328
334
|
}
|
|
329
335
|
this.#reconcileSegment();
|
|
330
336
|
if (segment !== null && this.#segment !== segment) this.#interrupted = true;
|
|
337
|
+
if (validateAxis && context.axis !== null && !this.#isAxisAllowed(context.mode, context.axis)) this.#interrupted = true;
|
|
331
338
|
return this.#canApplyInput();
|
|
332
339
|
}
|
|
333
340
|
/**
|
|
@@ -344,7 +351,7 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
344
351
|
};
|
|
345
352
|
const controls = this.#controls;
|
|
346
353
|
controls[key] = value;
|
|
347
|
-
this.#afterCallback(context);
|
|
354
|
+
this.#afterCallback(context, key === "axis");
|
|
348
355
|
}
|
|
349
356
|
/**
|
|
350
357
|
* Applies mode, space, and axis button transitions from the current frame.
|
|
@@ -401,7 +408,10 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
401
408
|
* @param axis - Axis requested by the gamepad button mapping.
|
|
402
409
|
*/
|
|
403
410
|
#selectAxis(axis) {
|
|
404
|
-
if (!this.#isAxisAllowed(this.#controls.mode, axis))
|
|
411
|
+
if (!this.#isAxisAllowed(this.#controls.mode, axis)) {
|
|
412
|
+
if (this.#resolveAxis() === null) this.#setActiveAxis(null);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
405
415
|
this.#endTransform(false);
|
|
406
416
|
if (!this.#canApplyInput()) return;
|
|
407
417
|
this.#setActiveAxis(axis);
|
|
@@ -410,8 +420,7 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
410
420
|
* Selects the next visible composite axis available in the current mode.
|
|
411
421
|
*/
|
|
412
422
|
#cycleCompositeAxis() {
|
|
413
|
-
|
|
414
|
-
this.#cycleThroughAxes(validAxes, 1);
|
|
423
|
+
this.#cycleThroughAxes(COMPOSITE_AXES[this.#controls.mode], 1);
|
|
415
424
|
}
|
|
416
425
|
/**
|
|
417
426
|
* Cycles through all valid axes for the current mode.
|
|
@@ -419,17 +428,18 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
419
428
|
* @param direction - `1` for next axis, `-1` for previous axis.
|
|
420
429
|
*/
|
|
421
430
|
#cycleAxis(direction) {
|
|
422
|
-
this.#cycleThroughAxes(this.#
|
|
431
|
+
this.#cycleThroughAxes(MODE_AXES[this.#controls.mode], direction);
|
|
423
432
|
}
|
|
424
433
|
/**
|
|
425
|
-
* Moves the active axis through
|
|
434
|
+
* Moves the active axis through candidates permitted after end callbacks.
|
|
426
435
|
*
|
|
427
|
-
* @param
|
|
436
|
+
* @param candidates - Unfiltered candidate axes to cycle through.
|
|
428
437
|
* @param direction - `1` for next axis, `-1` for previous axis.
|
|
429
438
|
*/
|
|
430
|
-
#cycleThroughAxes(
|
|
439
|
+
#cycleThroughAxes(candidates, direction) {
|
|
431
440
|
this.#endTransform(false);
|
|
432
441
|
if (!this.#canApplyInput()) return;
|
|
442
|
+
const axes = this.#getVisibleAxes(candidates);
|
|
433
443
|
if (axes.length === 0) {
|
|
434
444
|
this.#setActiveAxis(null);
|
|
435
445
|
return;
|
|
@@ -454,11 +464,16 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
454
464
|
return current !== null && validAxes.includes(current) ? current : validAxes[0] ?? null;
|
|
455
465
|
}
|
|
456
466
|
/**
|
|
457
|
-
*
|
|
467
|
+
* Revalidates a candidate after end callbacks before updating axis memory
|
|
468
|
+
* and the control. An invalidated candidate interrupts this update.
|
|
458
469
|
*
|
|
459
470
|
* @param axis - Axis to activate, or `null` to clear selection.
|
|
460
471
|
*/
|
|
461
472
|
#setActiveAxis(axis) {
|
|
473
|
+
if (axis !== null && !this.#isAxisAllowed(this.#controls.mode, axis)) {
|
|
474
|
+
this.#interrupted = true;
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
462
477
|
this.#activeAxisByMode[this.#controls.mode] = axis;
|
|
463
478
|
if (this.#controls.axis !== axis) this.#writeProperty("axis", axis);
|
|
464
479
|
}
|
|
@@ -493,7 +508,8 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
493
508
|
return MODE_AXES[mode].includes(axis) && this.#isAxisVisible(axis);
|
|
494
509
|
}
|
|
495
510
|
/**
|
|
496
|
-
* Reads
|
|
511
|
+
* Reads the native helper's explicit axis and plane visibility flags.
|
|
512
|
+
* Camera-alignment hiding does not prohibit gamepad selection.
|
|
497
513
|
*
|
|
498
514
|
* @param axis - Axis whose visibility should be checked.
|
|
499
515
|
* @returns `true` when all components required by the axis are visible.
|
|
@@ -507,9 +523,9 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
507
523
|
case "XY": return controls.showX && controls.showY && controls.showXY;
|
|
508
524
|
case "YZ": return controls.showY && controls.showZ && controls.showYZ;
|
|
509
525
|
case "XZ": return controls.showX && controls.showZ && controls.showXZ;
|
|
510
|
-
case "XYZ":
|
|
511
|
-
case "XYZE": return controls.showX && controls.showY && controls.showZ;
|
|
512
|
-
case "E": return
|
|
526
|
+
case "XYZ": return controls.showX && controls.showY && controls.showZ && controls.showXY && controls.showYZ;
|
|
527
|
+
case "XYZE": return controls.showX && controls.showY && controls.showZ && controls.showXY && controls.showYZ && controls.showXYZE;
|
|
528
|
+
case "E": return controls.showX && controls.showY && controls.showZ && controls.showE;
|
|
513
529
|
}
|
|
514
530
|
}
|
|
515
531
|
/**
|
|
@@ -847,7 +863,7 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
847
863
|
*/
|
|
848
864
|
#updateCameraState(object) {
|
|
849
865
|
const camera = this.#controls.camera;
|
|
850
|
-
camera.
|
|
866
|
+
camera.updateWorldMatrix(true, false);
|
|
851
867
|
object.updateWorldMatrix(true, false);
|
|
852
868
|
this.#cameraRight.setFromMatrixColumn(camera.matrixWorld, 0).normalize();
|
|
853
869
|
this.#cameraUp.setFromMatrixColumn(camera.matrixWorld, 1).normalize();
|
|
@@ -855,25 +871,7 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
855
871
|
camera.getWorldPosition(this.#cameraWorldPosition);
|
|
856
872
|
this.#worldPosition.setFromMatrixPosition(object.matrixWorld);
|
|
857
873
|
this.#eye.copy(this.#cameraWorldPosition).sub(this.#worldPosition).normalize();
|
|
858
|
-
this.#
|
|
859
|
-
}
|
|
860
|
-
/**
|
|
861
|
-
* Computes world-space viewport size at the attached object's depth.
|
|
862
|
-
*
|
|
863
|
-
* @param camera - TransformControls camera.
|
|
864
|
-
*/
|
|
865
|
-
#updateViewSizeAtObjectDepth(camera) {
|
|
866
|
-
if (this.#isOrthographicCamera(camera)) {
|
|
867
|
-
this.#viewSize.set(Math.abs(camera.right - camera.left) / camera.zoom, Math.abs(camera.top - camera.bottom) / camera.zoom);
|
|
868
|
-
return;
|
|
869
|
-
}
|
|
870
|
-
if (this.#isPerspectiveCamera(camera)) {
|
|
871
|
-
const depth = Math.max(Number.EPSILON, this.#worldPosition.subVectors(this.#worldPosition, this.#cameraWorldPosition).dot(this.#cameraForward));
|
|
872
|
-
const height = 2 * Math.tan(camera.fov * Math.PI / 360) * depth;
|
|
873
|
-
this.#viewSize.set(height * camera.aspect, height);
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
this.#viewSize.set(1, 1);
|
|
874
|
+
getCameraViewSize(camera, this.#worldPosition, this.#viewSize, this.#cameraSpacePosition);
|
|
877
875
|
}
|
|
878
876
|
/**
|
|
879
877
|
* Resolves a transform axis letter to a normalized world-space direction.
|
|
@@ -1078,24 +1076,6 @@ var GamepadTransformControls = class extends GamepadControls {
|
|
|
1078
1076
|
for (const button of buttons) if (input.wasPressed(button)) startedButtons.add(button);
|
|
1079
1077
|
return startedButtons;
|
|
1080
1078
|
}
|
|
1081
|
-
/**
|
|
1082
|
-
* Narrows a Three.js camera to `PerspectiveCamera`.
|
|
1083
|
-
*
|
|
1084
|
-
* @param camera - Camera to inspect.
|
|
1085
|
-
* @returns `true` when the camera is perspective.
|
|
1086
|
-
*/
|
|
1087
|
-
#isPerspectiveCamera(camera) {
|
|
1088
|
-
return camera.isPerspectiveCamera === true;
|
|
1089
|
-
}
|
|
1090
|
-
/**
|
|
1091
|
-
* Narrows a Three.js camera to `OrthographicCamera`.
|
|
1092
|
-
*
|
|
1093
|
-
* @param camera - Camera to inspect.
|
|
1094
|
-
* @returns `true` when the camera is orthographic.
|
|
1095
|
-
*/
|
|
1096
|
-
#isOrthographicCamera(camera) {
|
|
1097
|
-
return camera.isOrthographicCamera === true;
|
|
1098
|
-
}
|
|
1099
1079
|
};
|
|
1100
1080
|
//#endregion
|
|
1101
1081
|
export { GamepadTransformControls };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/three-utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Reads the effective viewport dimensions at a world-space point.
|
|
4
|
+
*
|
|
5
|
+
* The caller updates camera world and projection matrices and owns both reusable
|
|
6
|
+
* vectors. View offsets change dimensions, not the point's accumulated position.
|
|
7
|
+
*
|
|
8
|
+
* @param camera - Camera whose current projection is used.
|
|
9
|
+
* @param worldPosition - World-space point, left unchanged.
|
|
10
|
+
* @param target - Receives viewport width and height in world units.
|
|
11
|
+
* @param cameraPosition - Scratch vector for camera-space depth.
|
|
12
|
+
* @returns The target vector, or a unit viewport for an unknown camera type.
|
|
13
|
+
*/
|
|
14
|
+
const getCameraViewSize = (camera, worldPosition, target, cameraPosition) => {
|
|
15
|
+
if (camera.isOrthographicCamera === true) {
|
|
16
|
+
const projection = camera.projectionMatrix.elements;
|
|
17
|
+
return target.set(Math.abs(2 / projection[0]), Math.abs(2 / projection[5]));
|
|
18
|
+
}
|
|
19
|
+
if (camera.isPerspectiveCamera === true) {
|
|
20
|
+
cameraPosition.copy(worldPosition).applyMatrix4(camera.matrixWorldInverse);
|
|
21
|
+
const depth = Math.max(Number.EPSILON, -cameraPosition.z);
|
|
22
|
+
return camera.getViewSize(depth, target);
|
|
23
|
+
}
|
|
24
|
+
return target.set(1, 1);
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { getCameraViewSize };
|
package/package.json
CHANGED