@kitware/vtk.js 30.0.0 → 30.1.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/BREAKING_CHANGES.md +3 -2
- package/Interaction/Manipulators/3DControllerModelSelectorManipulator/index.js +182 -0
- package/Interaction/Manipulators/3DControllerModelSelectorManipulator.d.ts +19 -0
- package/Interaction/Manipulators/CompositeVRManipulator.d.ts +9 -9
- package/Interaction/Manipulators/CompositeVRManipulator.js +2 -2
- package/Interaction/Manipulators/VRButtonPanManipulator.js +5 -5
- package/Interaction/Style/InteractorStyleHMDXR.d.ts +22 -0
- package/Interaction/Style/InteractorStyleHMDXR.js +50 -0
- package/Interaction/Style/InteractorStyleManipulator.js +20 -10
- package/Rendering/Core/Prop3D.d.ts +16 -1
- package/Rendering/Core/Prop3D.js +14 -0
- package/Rendering/Core/RenderWindowInteractor.d.ts +21 -5
- package/Rendering/Core/RenderWindowInteractor.js +43 -37
- package/Rendering/WebXR/RenderWindowHelper.js +66 -11
- package/index.d.ts +1 -0
- package/package.json +1 -1
package/BREAKING_CHANGES.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
## From 29.x to 30
|
|
2
2
|
|
|
3
|
-
- **ResliceCursorWidget.interactionEvent**: no longer pass an object of computeFocalPointOffset, canUpdateFocalPoint but simply the type of the handle that triggers the event.
|
|
4
|
-
|
|
3
|
+
- **ResliceCursorWidget.interactionEvent**: no longer pass an object of `{computeFocalPointOffset, canUpdateFocalPoint}` but simply the type of the handle that triggers the event (e.g. `InteractionMethodsName.RotateLine`). The removed values can easily be recomputed by the consumers of the event by checking the type of the handle. Regarding `computeFocalPointOffset`, it is no longer advised to compute focal point offset for each interaction, instead observing `startInteraction()` should be considered (see ResliceCursorWidget example).
|
|
4
|
+
- **ResliceCursorWidget.invokeInternalInteractionEvent(methodName)**: has been removed and should be replaced by `ResliceCursorWidget.invokeInteractionEvent(methodName)`.
|
|
5
|
+
- **ResliceCursorWidget.updateCameraPoints(renderer, viewType, resetFocalPoint, keepCenterFocalDistance, computeFocalPointOffset)** has lost the `keepCenterFocalDistance` parameter (because it was ALWAYS the negate of `computeFocalPointOffset`). The new signature is `ResliceCursorWidget.updateCameraPoints(renderer, viewType, resetFocalPoint, keepCenterFocalDistance, computeFocalPointOffset)`
|
|
5
6
|
|
|
6
7
|
## From 28.x to 29
|
|
7
8
|
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { vec3, vec4, quat, mat4 } from 'gl-matrix';
|
|
2
|
+
import vtkCompositeVRManipulator from '../CompositeVRManipulator.js';
|
|
3
|
+
import vtkPicker from '../../../Rendering/Core/Picker.js';
|
|
4
|
+
import { m as macro } from '../../../macros2.js';
|
|
5
|
+
import { States } from '../../../Rendering/Core/InteractorStyle/Constants.js';
|
|
6
|
+
|
|
7
|
+
// ----------------------------------------------------------------------------
|
|
8
|
+
// vtk3DControllerModelSelectorManipulator methods
|
|
9
|
+
// ----------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
function vtk3DControllerModelSelectorManipulator(publicAPI, model) {
|
|
12
|
+
model.classHierarchy.push('vtk3DControllerModelSelectorManipulator');
|
|
13
|
+
const picker = vtkPicker.newInstance();
|
|
14
|
+
|
|
15
|
+
// The current prop we are manipulating, if any.
|
|
16
|
+
let pickedProp;
|
|
17
|
+
|
|
18
|
+
// pre-allocate array buffers
|
|
19
|
+
const physicalToWorldMatrix = new Float64Array(16);
|
|
20
|
+
|
|
21
|
+
// arrays holding deltas from lastWorldPosition and lastOrientation
|
|
22
|
+
const translation = new Float64Array(3);
|
|
23
|
+
const rotation = new Float64Array(4);
|
|
24
|
+
const lastOrientationConjugate = new Float64Array(4);
|
|
25
|
+
const orientationAxis = new Float64Array(3);
|
|
26
|
+
|
|
27
|
+
// arrays holding the transform
|
|
28
|
+
const computedTransform = new Float64Array(16);
|
|
29
|
+
const computedTransformRotation = new Float64Array(4);
|
|
30
|
+
|
|
31
|
+
// arrays holding the current state of pickedProp.
|
|
32
|
+
const transposedPropMatrix = new Float64Array(16);
|
|
33
|
+
const propCurrentOrientation = new Float64Array(4);
|
|
34
|
+
const propCurrentOrientationConjugate = new Float64Array(4);
|
|
35
|
+
|
|
36
|
+
// arrays holding the new properties that must be assigned to pickedProp.
|
|
37
|
+
const propNewTranslation = new Float64Array(3);
|
|
38
|
+
const propNewScaling = new Float64Array(3);
|
|
39
|
+
const propNewOrientation = new Float64Array(4);
|
|
40
|
+
function applyPositionAndOrientationToProp(prop, worldPosition, orientation) {
|
|
41
|
+
vec3.subtract(translation, worldPosition, model.lastWorldPosition);
|
|
42
|
+
quat.conjugate(lastOrientationConjugate, model.lastOrientation);
|
|
43
|
+
quat.multiply(rotation, orientation, lastOrientationConjugate);
|
|
44
|
+
quat.normalize(rotation, rotation);
|
|
45
|
+
const rotationAngle = quat.getAxisAngle(orientationAxis, rotation);
|
|
46
|
+
|
|
47
|
+
// reset to identity
|
|
48
|
+
mat4.identity(computedTransform);
|
|
49
|
+
|
|
50
|
+
// compute transform
|
|
51
|
+
mat4.translate(computedTransform, computedTransform, worldPosition);
|
|
52
|
+
mat4.rotate(computedTransform, computedTransform, rotationAngle, orientationAxis);
|
|
53
|
+
mat4.translate(computedTransform, computedTransform, vec3.negate(new Float64Array(3), worldPosition));
|
|
54
|
+
mat4.translate(computedTransform, computedTransform, translation);
|
|
55
|
+
|
|
56
|
+
// lookup the prop internal matrix
|
|
57
|
+
mat4.transpose(transposedPropMatrix, prop.getMatrix());
|
|
58
|
+
// apply the new computedTransform to the prop internal matrix
|
|
59
|
+
mat4.multiply(computedTransform, computedTransform, transposedPropMatrix);
|
|
60
|
+
|
|
61
|
+
// Multiply the computedTransform with the current prop orientation to get the delta
|
|
62
|
+
// that must be applied to the prop
|
|
63
|
+
mat4.getRotation(computedTransformRotation, computedTransform);
|
|
64
|
+
prop.getOrientationQuaternion(propCurrentOrientation);
|
|
65
|
+
quat.conjugate(propCurrentOrientationConjugate, propCurrentOrientation);
|
|
66
|
+
quat.multiply(propNewOrientation, propCurrentOrientationConjugate, computedTransformRotation);
|
|
67
|
+
quat.normalize(propNewOrientation, propNewOrientation);
|
|
68
|
+
mat4.getTranslation(propNewTranslation, computedTransform);
|
|
69
|
+
mat4.getScaling(propNewScaling, computedTransform);
|
|
70
|
+
|
|
71
|
+
// Update the prop internal matrix
|
|
72
|
+
prop.setPosition(...propNewTranslation);
|
|
73
|
+
prop.setScale(...propNewScaling);
|
|
74
|
+
prop.rotateQuaternion(propNewOrientation);
|
|
75
|
+
}
|
|
76
|
+
function releasePickedProp() {
|
|
77
|
+
model.lastOrientation = null;
|
|
78
|
+
model.lastWorldPosition = null;
|
|
79
|
+
if (pickedProp) {
|
|
80
|
+
pickedProp.setDragable(true);
|
|
81
|
+
}
|
|
82
|
+
pickedProp = null;
|
|
83
|
+
}
|
|
84
|
+
publicAPI.onButton3D = (interactorStyle, renderer, state, eventData) => {
|
|
85
|
+
// If the button is not pressed, clear the state
|
|
86
|
+
if (!eventData.pressed) {
|
|
87
|
+
releasePickedProp();
|
|
88
|
+
return macro.VOID;
|
|
89
|
+
}
|
|
90
|
+
const camera = renderer.getActiveCamera();
|
|
91
|
+
camera.getPhysicalToWorldMatrix(physicalToWorldMatrix);
|
|
92
|
+
const {
|
|
93
|
+
targetPosition,
|
|
94
|
+
targetOrientation
|
|
95
|
+
} = eventData;
|
|
96
|
+
|
|
97
|
+
// Since targetPosition is in physical coordinates,
|
|
98
|
+
// transform it using the physicalToWorldMatrix to get it in world coordinates
|
|
99
|
+
const targetRayWorldPosition = vec3.transformMat4([], [targetPosition.x, targetPosition.y, targetPosition.z], physicalToWorldMatrix);
|
|
100
|
+
const targetRayWorldDirection = camera.physicalOrientationToWorldDirection([targetOrientation.x, targetOrientation.y, targetOrientation.z, targetOrientation.w]);
|
|
101
|
+
const dist = renderer.getActiveCamera().getClippingRange()[1];
|
|
102
|
+
const rayPoint1 = [...targetRayWorldPosition, 1.0];
|
|
103
|
+
const rayPoint2 = [rayPoint1[0] - targetRayWorldDirection[0] * dist, rayPoint1[1] - targetRayWorldDirection[1] * dist, rayPoint1[2] - targetRayWorldDirection[2] * dist, 1.0];
|
|
104
|
+
|
|
105
|
+
// Perform picking on the given renderer
|
|
106
|
+
picker.pick3DPoint(rayPoint1, rayPoint2, renderer);
|
|
107
|
+
const props = picker.getActors();
|
|
108
|
+
|
|
109
|
+
// If we have picked props, store the first one.
|
|
110
|
+
if (props.length > 0 && props[0].getNestedDragable()) {
|
|
111
|
+
pickedProp = props[0];
|
|
112
|
+
|
|
113
|
+
// prevent the prop from being dragged somewhere else
|
|
114
|
+
pickedProp.setDragable(false);
|
|
115
|
+
} else {
|
|
116
|
+
releasePickedProp();
|
|
117
|
+
}
|
|
118
|
+
return macro.EVENT_ABORT;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// pre-allocation to reduce gc in onMove3D
|
|
122
|
+
const currentTargetRayWorldPosition = new Float64Array(3);
|
|
123
|
+
const currentTargetRayOrientation = new Float64Array(4);
|
|
124
|
+
publicAPI.onMove3D = (interactorStyle, renderer, state, eventData) => {
|
|
125
|
+
// If we are not interacting with any prop, we have nothing to do.
|
|
126
|
+
// Also check for dragable
|
|
127
|
+
if (state !== States.IS_CAMERA_POSE || pickedProp == null) {
|
|
128
|
+
return macro.VOID;
|
|
129
|
+
}
|
|
130
|
+
const camera = renderer.getActiveCamera();
|
|
131
|
+
camera.getPhysicalToWorldMatrix(physicalToWorldMatrix);
|
|
132
|
+
const {
|
|
133
|
+
targetPosition
|
|
134
|
+
} = eventData;
|
|
135
|
+
vec3.transformMat4(currentTargetRayWorldPosition, [targetPosition.x, targetPosition.y, targetPosition.z], physicalToWorldMatrix);
|
|
136
|
+
|
|
137
|
+
// this is a unit quaternion
|
|
138
|
+
vec4.set(currentTargetRayOrientation, eventData.targetOrientation.x, eventData.targetOrientation.y, eventData.targetOrientation.z, eventData.targetOrientation.w);
|
|
139
|
+
if (model.lastWorldPosition && model.lastOrientation) {
|
|
140
|
+
applyPositionAndOrientationToProp(pickedProp, currentTargetRayWorldPosition, currentTargetRayOrientation);
|
|
141
|
+
} else {
|
|
142
|
+
// allocate
|
|
143
|
+
model.lastWorldPosition = new Float64Array(3);
|
|
144
|
+
model.lastOrientation = new Float64Array(4);
|
|
145
|
+
}
|
|
146
|
+
vec3.copy(model.lastWorldPosition, currentTargetRayWorldPosition);
|
|
147
|
+
vec4.copy(model.lastOrientation, currentTargetRayOrientation);
|
|
148
|
+
return macro.EVENT_ABORT;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ----------------------------------------------------------------------------
|
|
153
|
+
// Object factory
|
|
154
|
+
// ----------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
const DEFAULT_VALUES = {};
|
|
157
|
+
|
|
158
|
+
// ----------------------------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
function extend(publicAPI, model) {
|
|
161
|
+
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
162
|
+
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
163
|
+
macro.get(publicAPI, model, ['lastWorldPosition', 'lastOrientation']);
|
|
164
|
+
macro.obj(publicAPI, model);
|
|
165
|
+
vtkCompositeVRManipulator.extend(publicAPI, model, initialValues);
|
|
166
|
+
|
|
167
|
+
// Object specific methods
|
|
168
|
+
vtk3DControllerModelSelectorManipulator(publicAPI, model);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ----------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
const newInstance = macro.newInstance(extend, 'vtk3DControllerModelSelectorManipulator');
|
|
174
|
+
|
|
175
|
+
// ----------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
var vtk3DControllerModelSelectorManipulator$1 = {
|
|
178
|
+
newInstance,
|
|
179
|
+
extend
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export { vtk3DControllerModelSelectorManipulator$1 as default, extend, newInstance };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import vtkCompositeVRManipulator from './CompositeVRManipulator';
|
|
2
|
+
|
|
3
|
+
export interface vtk3DControllerModelSelectorManipulator
|
|
4
|
+
extends vtkCompositeVRManipulator {}
|
|
5
|
+
|
|
6
|
+
export interface I3DControllerModelSelectorManipulatorInitialValues
|
|
7
|
+
extends vtkCompositeVRManipulator {}
|
|
8
|
+
|
|
9
|
+
export function extend(
|
|
10
|
+
publicAPI: object,
|
|
11
|
+
model: object,
|
|
12
|
+
initialValues?: I3DControllerModelSelectorManipulatorInitialValues
|
|
13
|
+
): void;
|
|
14
|
+
|
|
15
|
+
export const vtk3DControllerModelSelectorManipulator: {
|
|
16
|
+
extend: typeof extend;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default vtk3DControllerModelSelectorManipulator;
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
import { States } from './../../Rendering/Core/InteractorStyle/Constants';
|
|
2
2
|
import vtkRenderer from './../../Rendering/Core/Renderer';
|
|
3
|
-
import
|
|
3
|
+
import vtkInteractorObserver from './../../Rendering/Core/InteractorObserver';
|
|
4
4
|
import {
|
|
5
5
|
Device,
|
|
6
6
|
Input,
|
|
7
7
|
} from './../../Rendering/Core/RenderWindowInteractor/Constants';
|
|
8
|
+
import {
|
|
9
|
+
I3DEvent,
|
|
10
|
+
IButton3DEvent,
|
|
11
|
+
} from './../../Rendering/Core/RenderWindowInteractor';
|
|
8
12
|
|
|
9
13
|
export interface vtkCompositeVRManipulator {
|
|
10
14
|
onButton3D(
|
|
11
|
-
|
|
15
|
+
interactorStyle: vtkInteractorObserver,
|
|
12
16
|
renderer: vtkRenderer,
|
|
13
17
|
state: States,
|
|
14
|
-
|
|
15
|
-
input: Input,
|
|
16
|
-
pressed: boolean
|
|
18
|
+
eventData: IButton3DEvent
|
|
17
19
|
): void;
|
|
18
20
|
|
|
19
21
|
onMove3D(
|
|
20
|
-
|
|
22
|
+
interactorStyle: vtkInteractorObserver,
|
|
21
23
|
renderer: vtkRenderer,
|
|
22
24
|
state: States,
|
|
23
|
-
|
|
24
|
-
input: Input,
|
|
25
|
-
pressed: boolean
|
|
25
|
+
eventData: I3DEvent
|
|
26
26
|
): void;
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -8,8 +8,8 @@ import { Device, Input } from '../../Rendering/Core/RenderWindowInteractor/Const
|
|
|
8
8
|
function vtkCompositeVRManipulator(publicAPI, model) {
|
|
9
9
|
// Set our className
|
|
10
10
|
model.classHierarchy.push('vtkCompositeVRManipulator');
|
|
11
|
-
publicAPI.onButton3D = (
|
|
12
|
-
publicAPI.onMove3D = (
|
|
11
|
+
publicAPI.onButton3D = (interactorStyle, renderer, state, eventData) => {};
|
|
12
|
+
publicAPI.onMove3D = (interactorStyle, renderer, state, eventData) => {};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
// ----------------------------------------------------------------------------
|
|
@@ -10,14 +10,14 @@ import { States } from '../../Rendering/Core/InteractorStyle/Constants.js';
|
|
|
10
10
|
function vtkVRButtonPanManipulator(publicAPI, model) {
|
|
11
11
|
// Set our className
|
|
12
12
|
model.classHierarchy.push('vtkVRButtonPanManipulator');
|
|
13
|
-
publicAPI.onButton3D = (interactorStyle, renderer, state,
|
|
14
|
-
if (pressed) {
|
|
13
|
+
publicAPI.onButton3D = (interactorStyle, renderer, state, eventData) => {
|
|
14
|
+
if (eventData.pressed) {
|
|
15
15
|
interactorStyle.startCameraPose();
|
|
16
16
|
} else if (state === States.IS_CAMERA_POSE) {
|
|
17
17
|
interactorStyle.endCameraPose();
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
|
-
publicAPI.onMove3D = (interactorStyle, renderer, state,
|
|
20
|
+
publicAPI.onMove3D = (interactorStyle, renderer, state, eventData) => {
|
|
21
21
|
if (state !== States.IS_CAMERA_POSE) {
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
@@ -28,13 +28,13 @@ function vtkVRButtonPanManipulator(publicAPI, model) {
|
|
|
28
28
|
const oldTrans = camera.getPhysicalTranslation();
|
|
29
29
|
|
|
30
30
|
// look at the y axis to determine how fast / what direction to move
|
|
31
|
-
const speed =
|
|
31
|
+
const speed = eventData.gamepad.axes[1];
|
|
32
32
|
|
|
33
33
|
// 0.05 meters / frame movement
|
|
34
34
|
const pscale = speed * 0.05 * camera.getPhysicalScale();
|
|
35
35
|
|
|
36
36
|
// convert orientation to world coordinate direction
|
|
37
|
-
const dir = camera.physicalOrientationToWorldDirection(
|
|
37
|
+
const dir = camera.physicalOrientationToWorldDirection(eventData.orientation);
|
|
38
38
|
camera.setPhysicalTranslation(oldTrans[0] + dir[0] * pscale, oldTrans[1] + dir[1] * pscale, oldTrans[2] + dir[2] * pscale);
|
|
39
39
|
};
|
|
40
40
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import vtkInteractorStyleManipulator, { IInteractorStyleManipulatorInitialValues } from './InteractorStyleManipulator';
|
|
2
|
+
|
|
3
|
+
export interface vtkInteractorStyleHMDXR extends vtkInteractorStyleManipulator {}
|
|
4
|
+
|
|
5
|
+
export interface IInteractorStyleHMDXRInitialValues extends IInteractorStyleManipulatorInitialValues {}
|
|
6
|
+
|
|
7
|
+
export function newInstance(
|
|
8
|
+
initialValues?: IInteractorStyleHMDXRInitialValues
|
|
9
|
+
): vtkInteractorStyleHMDXR;
|
|
10
|
+
|
|
11
|
+
export function extend(
|
|
12
|
+
publicAPI: object,
|
|
13
|
+
model: object,
|
|
14
|
+
initialValues?: IInteractorStyleHMDXRInitialValues
|
|
15
|
+
): void;
|
|
16
|
+
|
|
17
|
+
export const vtkInteractorStyleHMDXR: {
|
|
18
|
+
newInstance: typeof newInstance;
|
|
19
|
+
extend: typeof extend;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default vtkInteractorStyleHMDXR;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { m as macro } from '../../macros2.js';
|
|
2
|
+
import vtkInteractorStyleManipulator from './InteractorStyleManipulator.js';
|
|
3
|
+
import vtk3DControllerModelSelectorManipulator from '../Manipulators/3DControllerModelSelectorManipulator/index.js';
|
|
4
|
+
import { Device, Input } from '../../Rendering/Core/RenderWindowInteractor/Constants.js';
|
|
5
|
+
|
|
6
|
+
function vtkInteractorStyleHMDXR(publicAPI, model) {
|
|
7
|
+
model.classHierarchy.push('vtkInteractorStyleHMDXR');
|
|
8
|
+
const leftHandManipulator = vtk3DControllerModelSelectorManipulator.newInstance({
|
|
9
|
+
device: Device.LeftController,
|
|
10
|
+
input: Input.A
|
|
11
|
+
});
|
|
12
|
+
const rightHandManipulator = vtk3DControllerModelSelectorManipulator.newInstance({
|
|
13
|
+
device: Device.RightController,
|
|
14
|
+
input: Input.A
|
|
15
|
+
});
|
|
16
|
+
publicAPI.addVRManipulator(leftHandManipulator);
|
|
17
|
+
publicAPI.addVRManipulator(rightHandManipulator);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ----------------------------------------------------------------------------
|
|
21
|
+
// Object factory
|
|
22
|
+
// ----------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
const DEFAULT_VALUES = {};
|
|
25
|
+
|
|
26
|
+
// ----------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
function extend(publicAPI, model) {
|
|
29
|
+
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
30
|
+
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
31
|
+
|
|
32
|
+
// Inheritance
|
|
33
|
+
vtkInteractorStyleManipulator.extend(publicAPI, model, initialValues);
|
|
34
|
+
|
|
35
|
+
// Object specific methods
|
|
36
|
+
vtkInteractorStyleHMDXR(publicAPI, model);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ----------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
const newInstance = macro.newInstance(extend, 'vtkInteractorStyleHMDXR');
|
|
42
|
+
|
|
43
|
+
// ----------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
var index = {
|
|
46
|
+
newInstance,
|
|
47
|
+
extend
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export { index as default, extend, newInstance };
|
|
@@ -118,6 +118,7 @@ const STATIC = {
|
|
|
118
118
|
function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
119
119
|
// Set our className
|
|
120
120
|
model.classHierarchy.push('vtkInteractorStyleManipulator');
|
|
121
|
+
model.currentVRManipulators = new Map();
|
|
121
122
|
model.mouseManipulators = [];
|
|
122
123
|
model.keyboardManipulators = [];
|
|
123
124
|
model.vrManipulators = [];
|
|
@@ -246,13 +247,20 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
246
247
|
}
|
|
247
248
|
|
|
248
249
|
// Look for a matching 3D camera interactor.
|
|
249
|
-
|
|
250
|
-
if (
|
|
251
|
-
|
|
250
|
+
const manipulator = publicAPI.findVRManipulator(ed.device, ed.input, ed.pressed);
|
|
251
|
+
if (manipulator) {
|
|
252
|
+
// register the manipulator for this device
|
|
253
|
+
model.currentVRManipulators.set(ed.device, manipulator);
|
|
254
|
+
manipulator.onButton3D(publicAPI, ed.pokedRenderer, model.state, ed);
|
|
252
255
|
if (ed.pressed) {
|
|
253
256
|
publicAPI.startCameraPose();
|
|
254
257
|
} else {
|
|
255
|
-
|
|
258
|
+
model.currentVRManipulators.delete(ed.device);
|
|
259
|
+
|
|
260
|
+
// make sure we don't end camera pose if other VR manipulators are currently interacting
|
|
261
|
+
if (model.currentVRManipulators.size === 0) {
|
|
262
|
+
publicAPI.endCameraPose();
|
|
263
|
+
}
|
|
256
264
|
}
|
|
257
265
|
} else {
|
|
258
266
|
vtkDebugMacro('No manipulator found');
|
|
@@ -261,8 +269,9 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
261
269
|
|
|
262
270
|
//-------------------------------------------------------------------------
|
|
263
271
|
publicAPI.handleMove3D = ed => {
|
|
264
|
-
|
|
265
|
-
|
|
272
|
+
const manipulator = model.currentVRManipulators.get(ed.device);
|
|
273
|
+
if (manipulator && model.state === States.IS_CAMERA_POSE) {
|
|
274
|
+
manipulator.onMove3D(publicAPI, ed.pokedRenderer, model.state, ed);
|
|
266
275
|
}
|
|
267
276
|
};
|
|
268
277
|
|
|
@@ -576,7 +585,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
576
585
|
// Object factory
|
|
577
586
|
// ----------------------------------------------------------------------------
|
|
578
587
|
|
|
579
|
-
const
|
|
588
|
+
const defaultValues = initialValues => ({
|
|
580
589
|
cachedMousePosition: null,
|
|
581
590
|
currentManipulator: null,
|
|
582
591
|
currentWheelManipulator: null,
|
|
@@ -585,14 +594,15 @@ const DEFAULT_VALUES = {
|
|
|
585
594
|
// vrManipulators: null,
|
|
586
595
|
// gestureManipulators: null,
|
|
587
596
|
centerOfRotation: [0, 0, 0],
|
|
588
|
-
rotationFactor: 1
|
|
589
|
-
|
|
597
|
+
rotationFactor: 1,
|
|
598
|
+
...initialValues
|
|
599
|
+
});
|
|
590
600
|
|
|
591
601
|
// ----------------------------------------------------------------------------
|
|
592
602
|
|
|
593
603
|
function extend(publicAPI, model) {
|
|
594
604
|
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
595
|
-
Object.assign(model,
|
|
605
|
+
Object.assign(model, defaultValues(initialValues));
|
|
596
606
|
|
|
597
607
|
// Inheritance
|
|
598
608
|
vtkInteractorStyle.extend(publicAPI, model, initialValues);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mat4 } from "gl-matrix";
|
|
1
|
+
import { mat4, quat } from "gl-matrix";
|
|
2
2
|
import { Bounds, Vector3, Range } from './../../types';
|
|
3
3
|
import vtkProp, { IPropInitialValues } from './Prop';
|
|
4
4
|
|
|
@@ -88,6 +88,13 @@ export interface vtkProp3D extends vtkProp {
|
|
|
88
88
|
*/
|
|
89
89
|
getOrientationWXYZ(): number[];
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Get the orientation quaternion of the Prop3D.
|
|
93
|
+
* out is optional and will be created if not supplied.
|
|
94
|
+
* @param {quat | undefined} out
|
|
95
|
+
*/
|
|
96
|
+
getOrientationQuaternion(out?: quat): quat;
|
|
97
|
+
|
|
91
98
|
/**
|
|
92
99
|
* Get a reference to the Prop3D’s 4x4 composite matrix.
|
|
93
100
|
* Get the matrix from the position, origin, scale and orientation This
|
|
@@ -167,6 +174,14 @@ export interface vtkProp3D extends vtkProp {
|
|
|
167
174
|
*/
|
|
168
175
|
rotateWXYZ(degrees: number, x: number, y: number, z: number): void;
|
|
169
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Rotate the Prop3D by the provided orientation quaternion.
|
|
179
|
+
* If the provided quaternion is identity (~epsilon), this function does nothing.
|
|
180
|
+
* The quaternion should follow the gl-matrix convention: [x,y,z,w]
|
|
181
|
+
* @param {quat} orientationQuaternion The quaternion to rotate the prop by.
|
|
182
|
+
*/
|
|
183
|
+
rotateQuaternion(orientationQuaternion: quat): void;
|
|
184
|
+
|
|
170
185
|
/**
|
|
171
186
|
* Orientation is specified as X, Y and Z rotations in that order,
|
|
172
187
|
* but they are performed as RotateZ, RotateX, and finally RotateY.
|
package/Rendering/Core/Prop3D.js
CHANGED
|
@@ -4,6 +4,8 @@ import vtkBoundingBox from '../../Common/DataModel/BoundingBox.js';
|
|
|
4
4
|
import { A as degreesFromRadians, r as radiansFromDegrees, a as areMatricesEqual } from '../../Common/Core/Math/index.js';
|
|
5
5
|
import vtkProp from './Prop.js';
|
|
6
6
|
|
|
7
|
+
const VTK_EPSILON = 1e-6;
|
|
8
|
+
|
|
7
9
|
// ----------------------------------------------------------------------------
|
|
8
10
|
// vtkProp3D methods
|
|
9
11
|
// ----------------------------------------------------------------------------
|
|
@@ -22,6 +24,10 @@ function vtkProp3D(publicAPI, model) {
|
|
|
22
24
|
const w = quat.getAxisAngle(oaxis, q);
|
|
23
25
|
return [degreesFromRadians(w), oaxis[0], oaxis[1], oaxis[2]];
|
|
24
26
|
};
|
|
27
|
+
publicAPI.getOrientationQuaternion = function () {
|
|
28
|
+
let out = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
29
|
+
return mat4.getRotation(out, model.rotation);
|
|
30
|
+
};
|
|
25
31
|
publicAPI.rotateX = val => {
|
|
26
32
|
if (val === 0.0) {
|
|
27
33
|
return;
|
|
@@ -57,6 +63,14 @@ function vtkProp3D(publicAPI, model) {
|
|
|
57
63
|
mat4.multiply(model.rotation, model.rotation, quatMat);
|
|
58
64
|
publicAPI.modified();
|
|
59
65
|
};
|
|
66
|
+
publicAPI.rotateQuaternion = orientationQuaternion => {
|
|
67
|
+
if (Math.abs(orientationQuaternion[3]) >= 1 - VTK_EPSILON) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const oriQuatMat = mat4.fromQuat(new Float64Array(16), orientationQuaternion);
|
|
71
|
+
mat4.multiply(model.rotation, model.rotation, oriQuatMat);
|
|
72
|
+
publicAPI.modified();
|
|
73
|
+
};
|
|
60
74
|
publicAPI.setOrientation = (x, y, z) => {
|
|
61
75
|
if (x === model.orientation[0] && y === model.orientation[1] && z === model.orientation[2]) {
|
|
62
76
|
return false;
|
|
@@ -81,6 +81,20 @@ export interface IRenderWindowInteractorEvent {
|
|
|
81
81
|
type: InteractorEventType;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
export interface I3DEvent {
|
|
85
|
+
gamepad: Gamepad;
|
|
86
|
+
position: DOMPointReadOnly;
|
|
87
|
+
orientation: DOMPointReadOnly;
|
|
88
|
+
targetPosition: DOMPointReadOnly;
|
|
89
|
+
targetOrientation: DOMPointReadOnly;
|
|
90
|
+
device: Device;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface IButton3DEvent extends I3DEvent {
|
|
94
|
+
pressed: boolean;
|
|
95
|
+
input: Input;
|
|
96
|
+
}
|
|
97
|
+
|
|
84
98
|
export interface vtkRenderWindowInteractor extends vtkObject {
|
|
85
99
|
|
|
86
100
|
/**
|
|
@@ -678,10 +692,11 @@ export interface vtkRenderWindowInteractor extends vtkObject {
|
|
|
678
692
|
animationEvent(args: any): any;
|
|
679
693
|
|
|
680
694
|
/**
|
|
681
|
-
*
|
|
695
|
+
* Triggers the 'Button3D' event.
|
|
696
|
+
*
|
|
682
697
|
* @param args
|
|
683
698
|
*/
|
|
684
|
-
button3DEvent(
|
|
699
|
+
button3DEvent(eventPayload: IButton3DEvent): void;
|
|
685
700
|
|
|
686
701
|
/**
|
|
687
702
|
*
|
|
@@ -804,10 +819,11 @@ export interface vtkRenderWindowInteractor extends vtkObject {
|
|
|
804
819
|
mouseWheelEvent(args: any): any;
|
|
805
820
|
|
|
806
821
|
/**
|
|
807
|
-
*
|
|
808
|
-
*
|
|
822
|
+
* Triggers the 'Move3D' event.
|
|
823
|
+
*
|
|
824
|
+
* @param eventPayload
|
|
809
825
|
*/
|
|
810
|
-
move3DEvent(
|
|
826
|
+
move3DEvent(eventPayload: I3DEvent): void;
|
|
811
827
|
|
|
812
828
|
/**
|
|
813
829
|
*
|
|
@@ -481,45 +481,51 @@ function vtkRenderWindowInteractor(publicAPI, model) {
|
|
|
481
481
|
// watch for when buttons change state and fire events
|
|
482
482
|
xrSession.inputSources.forEach(inputSource => {
|
|
483
483
|
const gripPose = inputSource.gripSpace == null ? null : xrFrame.getPose(inputSource.gripSpace, xrRefSpace);
|
|
484
|
-
const
|
|
484
|
+
const targetRayPose = inputSource.gripSpace == null ? null : xrFrame.getPose(inputSource.targetRaySpace, xrRefSpace);
|
|
485
|
+
const gamepad = inputSource.gamepad;
|
|
485
486
|
const hand = inputSource.handedness;
|
|
486
|
-
if (
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
}
|
|
500
|
-
for (let b = 0; b < gp.buttons.length; ++b) {
|
|
501
|
-
if (!(b in model.lastGamepadValues[gp.index][hand].buttons)) {
|
|
502
|
-
model.lastGamepadValues[gp.index][hand].buttons[b] = false;
|
|
503
|
-
}
|
|
504
|
-
if (model.lastGamepadValues[gp.index][hand].buttons[b] !== gp.buttons[b].pressed && gripPose != null) {
|
|
505
|
-
publicAPI.button3DEvent({
|
|
506
|
-
gamepad: gp,
|
|
507
|
-
position: gripPose.transform.position,
|
|
508
|
-
orientation: gripPose.transform.orientation,
|
|
509
|
-
pressed: gp.buttons[b].pressed,
|
|
510
|
-
device: inputSource.handedness === 'left' ? Device.LeftController : Device.RightController,
|
|
511
|
-
input: deviceInputMap[gp.mapping] && deviceInputMap[gp.mapping][b] ? deviceInputMap[gp.mapping][b] : Input.Trigger
|
|
512
|
-
});
|
|
513
|
-
model.lastGamepadValues[gp.index][hand].buttons[b] = gp.buttons[b].pressed;
|
|
514
|
-
}
|
|
515
|
-
if (model.lastGamepadValues[gp.index][hand].buttons[b] && gripPose != null) {
|
|
516
|
-
publicAPI.move3DEvent({
|
|
517
|
-
gamepad: gp,
|
|
518
|
-
position: gripPose.transform.position,
|
|
519
|
-
orientation: gripPose.transform.orientation,
|
|
520
|
-
device: inputSource.handedness === 'left' ? Device.LeftController : Device.RightController
|
|
521
|
-
});
|
|
487
|
+
if (!gamepad) {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (!(gamepad.index in model.lastGamepadValues)) {
|
|
491
|
+
model.lastGamepadValues[gamepad.index] = {
|
|
492
|
+
left: {
|
|
493
|
+
buttons: {}
|
|
494
|
+
},
|
|
495
|
+
right: {
|
|
496
|
+
buttons: {}
|
|
497
|
+
},
|
|
498
|
+
none: {
|
|
499
|
+
buttons: {}
|
|
522
500
|
}
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
for (let buttonIdx = 0; buttonIdx < gamepad.buttons.length; ++buttonIdx) {
|
|
504
|
+
if (!(buttonIdx in model.lastGamepadValues[gamepad.index][hand].buttons)) {
|
|
505
|
+
model.lastGamepadValues[gamepad.index][hand].buttons[buttonIdx] = false;
|
|
506
|
+
}
|
|
507
|
+
if (model.lastGamepadValues[gamepad.index][hand].buttons[buttonIdx] !== gamepad.buttons[buttonIdx].pressed && gripPose != null) {
|
|
508
|
+
publicAPI.button3DEvent({
|
|
509
|
+
gamepad,
|
|
510
|
+
position: gripPose.transform.position,
|
|
511
|
+
orientation: gripPose.transform.orientation,
|
|
512
|
+
targetPosition: targetRayPose.transform.position,
|
|
513
|
+
targetOrientation: targetRayPose.transform.orientation,
|
|
514
|
+
pressed: gamepad.buttons[buttonIdx].pressed,
|
|
515
|
+
device: inputSource.handedness === 'left' ? Device.LeftController : Device.RightController,
|
|
516
|
+
input: deviceInputMap[gamepad.mapping] && deviceInputMap[gamepad.mapping][buttonIdx] ? deviceInputMap[gamepad.mapping][buttonIdx] : Input.Trigger
|
|
517
|
+
});
|
|
518
|
+
model.lastGamepadValues[gamepad.index][hand].buttons[buttonIdx] = gamepad.buttons[buttonIdx].pressed;
|
|
519
|
+
}
|
|
520
|
+
if (model.lastGamepadValues[gamepad.index][hand].buttons[buttonIdx] && gripPose != null) {
|
|
521
|
+
publicAPI.move3DEvent({
|
|
522
|
+
gamepad,
|
|
523
|
+
position: gripPose.transform.position,
|
|
524
|
+
orientation: gripPose.transform.orientation,
|
|
525
|
+
targetPosition: targetRayPose.transform.position,
|
|
526
|
+
targetOrientation: targetRayPose.transform.orientation,
|
|
527
|
+
device: inputSource.handedness === 'left' ? Device.LeftController : Device.RightController
|
|
528
|
+
});
|
|
523
529
|
}
|
|
524
530
|
}
|
|
525
531
|
});
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { m as macro } from '../../macros2.js';
|
|
2
2
|
import Constants from './RenderWindowHelper/Constants.js';
|
|
3
|
+
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
|
|
4
|
+
import vtkLineSource from '@kitware/vtk.js/Filters/Sources/LineSource';
|
|
5
|
+
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
|
|
3
6
|
import { GET_UNDERLYING_CONTEXT } from '../OpenGL/RenderWindow/ContextProxy.js';
|
|
7
|
+
import { vec3 } from 'gl-matrix';
|
|
4
8
|
|
|
5
9
|
const {
|
|
6
10
|
XrSessionTypes
|
|
@@ -11,6 +15,23 @@ const DEFAULT_RESET_FACTORS = {
|
|
|
11
15
|
translateZ: -1.5 // default translation initializes object in front of camera
|
|
12
16
|
};
|
|
13
17
|
|
|
18
|
+
function createRay() {
|
|
19
|
+
const targetRayLineSource = vtkLineSource.newInstance();
|
|
20
|
+
const targetRayMapper = vtkMapper.newInstance();
|
|
21
|
+
targetRayMapper.setInputConnection(targetRayLineSource.getOutputPort());
|
|
22
|
+
const targetRayActor = vtkActor.newInstance();
|
|
23
|
+
targetRayActor.getProperty().setColor(1, 0, 0);
|
|
24
|
+
targetRayActor.getProperty().setLineWidth(5);
|
|
25
|
+
targetRayActor.setMapper(targetRayMapper);
|
|
26
|
+
targetRayActor.setPickable(false);
|
|
27
|
+
return {
|
|
28
|
+
lineSource: targetRayLineSource,
|
|
29
|
+
mapper: targetRayMapper,
|
|
30
|
+
actor: targetRayActor,
|
|
31
|
+
visible: false
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
14
35
|
// ----------------------------------------------------------------------------
|
|
15
36
|
// vtkWebXRRenderWindowHelper methods
|
|
16
37
|
// ----------------------------------------------------------------------------
|
|
@@ -145,6 +166,36 @@ function vtkWebXRRenderWindowHelper(publicAPI, model) {
|
|
|
145
166
|
model.xrRender = async (t, frame) => {
|
|
146
167
|
const xrSession = frame.session;
|
|
147
168
|
const isXrSessionHMD = [XrSessionTypes.HmdVR, XrSessionTypes.HmdAR].includes(model.xrSessionType);
|
|
169
|
+
if (isXrSessionHMD && model.drawControllersRay && model.xrReferenceSpace) {
|
|
170
|
+
const renderer = model.renderWindow.getRenderable().getRenderers()[0];
|
|
171
|
+
const camera = renderer.getActiveCamera();
|
|
172
|
+
const physicalToWorldMatrix = [];
|
|
173
|
+
camera.getPhysicalToWorldMatrix(physicalToWorldMatrix);
|
|
174
|
+
xrSession.inputSources.forEach(inputSource => {
|
|
175
|
+
if (inputSource.targetRaySpace == null || inputSource.gripSpace == null || inputSource.targetRayMode !== 'tracked-pointer') {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (model.inputSourceToRay[inputSource.handedness] == null) {
|
|
179
|
+
model.inputSourceToRay[inputSource.handedness] = createRay();
|
|
180
|
+
}
|
|
181
|
+
const ray = model.inputSourceToRay[inputSource.handedness];
|
|
182
|
+
const targetRayPose = frame.getPose(inputSource.targetRaySpace, model.xrReferenceSpace);
|
|
183
|
+
if (targetRayPose == null) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const targetRayPosition = vec3.fromValues(targetRayPose.transform.position.x, targetRayPose.transform.position.y, targetRayPose.transform.position.z);
|
|
187
|
+
const dir = camera.physicalOrientationToWorldDirection([targetRayPose.transform.orientation.x, targetRayPose.transform.orientation.y, targetRayPose.transform.orientation.z, targetRayPose.transform.orientation.w]);
|
|
188
|
+
const targetRayWorldPosition = vec3.transformMat4([], targetRayPosition, physicalToWorldMatrix);
|
|
189
|
+
const dist = renderer.getActiveCamera().getClippingRange()[1];
|
|
190
|
+
if (!ray.visible) {
|
|
191
|
+
renderer.addActor(ray.actor);
|
|
192
|
+
ray.visible = true;
|
|
193
|
+
}
|
|
194
|
+
ray.lineSource.setPoint1(targetRayWorldPosition[0] - dir[0] * dist, targetRayWorldPosition[1] - dir[1] * dist, targetRayWorldPosition[2] - dir[2] * dist);
|
|
195
|
+
ray.lineSource.setPoint2(...targetRayWorldPosition);
|
|
196
|
+
});
|
|
197
|
+
model.renderWindow.render();
|
|
198
|
+
}
|
|
148
199
|
model.renderWindow.getRenderable().getInteractor().updateXRGamepads(xrSession, frame, model.xrReferenceSpace);
|
|
149
200
|
model.xrSceneFrame = model.xrSession.requestAnimationFrame(model.xrRender);
|
|
150
201
|
const xrPose = frame.getViewerPose(model.xrReferenceSpace);
|
|
@@ -202,27 +253,31 @@ function vtkWebXRRenderWindowHelper(publicAPI, model) {
|
|
|
202
253
|
// Object factory
|
|
203
254
|
// ----------------------------------------------------------------------------
|
|
204
255
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
256
|
+
function defaultValues() {
|
|
257
|
+
return {
|
|
258
|
+
initialized: false,
|
|
259
|
+
drawControllersRay: false,
|
|
260
|
+
inputSourceToRay: {},
|
|
261
|
+
initCanvasSize: null,
|
|
262
|
+
initBackground: null,
|
|
263
|
+
renderWindow: null,
|
|
264
|
+
xrSession: null,
|
|
265
|
+
xrSessionType: 0,
|
|
266
|
+
xrReferenceSpace: null
|
|
267
|
+
};
|
|
268
|
+
}
|
|
214
269
|
|
|
215
270
|
// ----------------------------------------------------------------------------
|
|
216
271
|
|
|
217
272
|
function extend(publicAPI, model) {
|
|
218
273
|
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
219
|
-
Object.assign(model,
|
|
274
|
+
Object.assign(model, defaultValues(), initialValues);
|
|
220
275
|
|
|
221
276
|
// Build VTK API
|
|
222
277
|
macro.obj(publicAPI, model);
|
|
223
278
|
macro.event(publicAPI, model, 'event');
|
|
224
279
|
macro.get(publicAPI, model, ['xrSession']);
|
|
225
|
-
macro.setGet(publicAPI, model, ['renderWindow']);
|
|
280
|
+
macro.setGet(publicAPI, model, ['renderWindow', 'drawControllersRay']);
|
|
226
281
|
|
|
227
282
|
// Object methods
|
|
228
283
|
vtkWebXRRenderWindowHelper(publicAPI, model);
|
package/index.d.ts
CHANGED
|
@@ -123,6 +123,7 @@
|
|
|
123
123
|
/// <reference path="./Interaction/Manipulators/MouseCameraTrackballZoomManipulator.d.ts" />
|
|
124
124
|
/// <reference path="./Interaction/Manipulators/MouseCameraTrackballZoomToMouseManipulator.d.ts" />
|
|
125
125
|
/// <reference path="./Interaction/Manipulators/MouseRangeManipulator.d.ts" />
|
|
126
|
+
/// <reference path="./Interaction/Style/InteractorStyleHMDXR.d.ts" />
|
|
126
127
|
/// <reference path="./Interaction/Style/InteractorStyleImage.d.ts" />
|
|
127
128
|
/// <reference path="./Interaction/Style/InteractorStyleManipulator.d.ts" />
|
|
128
129
|
/// <reference path="./Interaction/Style/InteractorStyleTrackballCamera.d.ts" />
|