three-stdlib 2.20.5 → 2.21.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/index.cjs.js +1 -1
- package/index.d.ts +1 -0
- package/libs/MotionControllers.cjs.js +1 -1
- package/libs/MotionControllers.d.ts +132 -0
- package/libs/MotionControllers.js +65 -13
- package/package.json +1 -1
- package/webxr/XRControllerModelFactory.cjs.js +1 -1
- package/webxr/XRControllerModelFactory.d.ts +12 -12
- package/webxr/XRControllerModelFactory.js +59 -26
package/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const
|
|
1
|
+
"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}Object.defineProperty(exports,"__esModule",{value:!0});var t=e(require("@babel/runtime/helpers/defineProperty"));const s={Handedness:Object.freeze({NONE:"none",LEFT:"left",RIGHT:"right"}),ComponentState:Object.freeze({DEFAULT:"default",TOUCHED:"touched",PRESSED:"pressed"}),ComponentProperty:Object.freeze({BUTTON:"button",X_AXIS:"xAxis",Y_AXIS:"yAxis",STATE:"state"}),ComponentType:Object.freeze({TRIGGER:"trigger",SQUEEZE:"squeeze",TOUCHPAD:"touchpad",THUMBSTICK:"thumbstick",BUTTON:"button"}),ButtonTouchThreshold:.05,AxisTouchThreshold:.1,VisualResponseProperty:Object.freeze({TRANSFORM:"transform",VISIBILITY:"visibility"})};async function o(e){const t=await fetch(e);if(t.ok)return t.json();throw new Error(t.statusText)}async function i(e){if(!e)throw new Error("No basePath supplied");return await o(`${e}/profilesList.json`)}const a={xAxis:0,yAxis:0,button:0,state:s.ComponentState.DEFAULT};class n{constructor(e){t.default(this,"value",void 0),t.default(this,"componentProperty",void 0),t.default(this,"states",void 0),t.default(this,"valueNodeName",void 0),t.default(this,"valueNodeProperty",void 0),t.default(this,"minNodeName",void 0),t.default(this,"maxNodeName",void 0),t.default(this,"valueNode",void 0),t.default(this,"minNode",void 0),t.default(this,"maxNode",void 0),this.componentProperty=e.componentProperty,this.states=e.states,this.valueNodeName=e.valueNodeName,this.valueNodeProperty=e.valueNodeProperty,this.valueNodeProperty===s.VisualResponseProperty.TRANSFORM&&(this.minNodeName=e.minNodeName,this.maxNodeName=e.maxNodeName),this.value=0,this.updateFromComponent(a)}updateFromComponent({xAxis:e,yAxis:t,button:o,state:i}){const{normalizedXAxis:a,normalizedYAxis:n}=function(e=0,t=0){let s=e,o=t;if(Math.sqrt(e*e+t*t)>1){const i=Math.atan2(t,e);s=Math.cos(i),o=Math.sin(i)}return{normalizedXAxis:.5*s+.5,normalizedYAxis:.5*o+.5}}(e,t);switch(this.componentProperty){case s.ComponentProperty.X_AXIS:this.value=this.states.includes(i)?a:.5;break;case s.ComponentProperty.Y_AXIS:this.value=this.states.includes(i)?n:.5;break;case s.ComponentProperty.BUTTON:this.value=this.states.includes(i)&&o?o:0;break;case s.ComponentProperty.STATE:this.valueNodeProperty===s.VisualResponseProperty.VISIBILITY?this.value=this.states.includes(i):this.value=this.states.includes(i)?1:0;break;default:throw new Error(`Unexpected visualResponse componentProperty ${this.componentProperty}`)}}}class r{constructor(e,o){if(t.default(this,"id",void 0),t.default(this,"values",void 0),t.default(this,"type",void 0),t.default(this,"gamepadIndices",void 0),t.default(this,"rootNodeName",void 0),t.default(this,"visualResponses",void 0),t.default(this,"touchPointNodeName",void 0),t.default(this,"touchPointNode",void 0),!(e&&o&&o.visualResponses&&o.gamepadIndices&&0!==Object.keys(o.gamepadIndices).length))throw new Error("Invalid arguments supplied");this.id=e,this.type=o.type,this.rootNodeName=o.rootNodeName,this.touchPointNodeName=o.touchPointNodeName,this.visualResponses={},Object.keys(o.visualResponses).forEach((e=>{const t=new n(o.visualResponses[e]);this.visualResponses[e]=t})),this.gamepadIndices=Object.assign({},o.gamepadIndices),this.values={state:s.ComponentState.DEFAULT,button:void 0!==this.gamepadIndices.button?0:void 0,xAxis:void 0!==this.gamepadIndices.xAxis?0:void 0,yAxis:void 0!==this.gamepadIndices.yAxis?0:void 0}}get data(){return{id:this.id,...this.values}}updateFromGamepad(e){if(this.values.state=s.ComponentState.DEFAULT,void 0!==this.gamepadIndices.button&&e.buttons.length>this.gamepadIndices.button){const t=e.buttons[this.gamepadIndices.button];this.values.button=t.value,this.values.button=this.values.button<0?0:this.values.button,this.values.button=this.values.button>1?1:this.values.button,t.pressed||1===this.values.button?this.values.state=s.ComponentState.PRESSED:(t.touched||this.values.button>s.ButtonTouchThreshold)&&(this.values.state=s.ComponentState.TOUCHED)}void 0!==this.gamepadIndices.xAxis&&e.axes.length>this.gamepadIndices.xAxis&&(this.values.xAxis=e.axes[this.gamepadIndices.xAxis],this.values.xAxis=this.values.xAxis<-1?-1:this.values.xAxis,this.values.xAxis=this.values.xAxis>1?1:this.values.xAxis,this.values.state===s.ComponentState.DEFAULT&&Math.abs(this.values.xAxis)>s.AxisTouchThreshold&&(this.values.state=s.ComponentState.TOUCHED)),void 0!==this.gamepadIndices.yAxis&&e.axes.length>this.gamepadIndices.yAxis&&(this.values.yAxis=e.axes[this.gamepadIndices.yAxis],this.values.yAxis=this.values.yAxis<-1?-1:this.values.yAxis,this.values.yAxis=this.values.yAxis>1?1:this.values.yAxis,this.values.state===s.ComponentState.DEFAULT&&Math.abs(this.values.yAxis)>s.AxisTouchThreshold&&(this.values.state=s.ComponentState.TOUCHED)),Object.values(this.visualResponses).forEach((e=>{e.updateFromComponent(this.values)}))}}exports.MotionController=class{constructor(e,s,o){if(t.default(this,"xrInputSource",void 0),t.default(this,"assetUrl",void 0),t.default(this,"layoutDescription",void 0),t.default(this,"id",void 0),t.default(this,"components",void 0),!e)throw new Error("No xrInputSource supplied");if(!s)throw new Error("No profile supplied");if(!s.layouts[e.handedness])throw new Error("No layout for "+e.handedness+" handedness");this.xrInputSource=e,this.assetUrl=o,this.id=s.profileId,this.layoutDescription=s.layouts[e.handedness],this.components={},Object.keys(this.layoutDescription.components).forEach((e=>{const t=this.layoutDescription.components[e];this.components[e]=new r(e,t)})),this.updateFromGamepad()}get gripSpace(){return this.xrInputSource.gripSpace}get targetRaySpace(){return this.xrInputSource.targetRaySpace}get data(){const e=[];return Object.values(this.components).forEach((t=>{e.push(t.data)})),e}updateFromGamepad(){Object.values(this.components).forEach((e=>{e.updateFromGamepad(this.xrInputSource.gamepad)}))}},exports.MotionControllerConstants=s,exports.fetchProfile=async function(e,t,s=null,a=!0){if(!e)throw new Error("No xrInputSource supplied");if(!t)throw new Error("No basePath supplied");const n=await i(t);let r;if(e.profiles.some((e=>{const s=n[e];return s&&(r={profileId:e,profilePath:`${t}/${s.path}`,deprecated:!!s.deprecated}),!!r})),!r){if(!s)throw new Error("No matching profile name found");const e=n[s];if(!e)throw new Error(`No matching profile name found and default profile "${s}" missing.`);r={profileId:s,profilePath:`${t}/${e.path}`,deprecated:!!e.deprecated}}const d=await o(r.profilePath);let u;if(a){let t;if(t="any"===e.handedness?d.layouts[Object.keys(d.layouts)[0]]:d.layouts[e.handedness],!t)throw new Error(`No matching handedness, ${e.handedness}, in profile ${r.profileId}`);t.assetPath&&(u=r.profilePath.replace("profile.json",t.assetPath))}return{profile:d,assetPath:u}},exports.fetchProfilesList=i;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { Object3D, XRGamepad, XRHandedness, XRInputSource } from 'three';
|
|
2
|
+
interface GamepadIndices {
|
|
3
|
+
button: number;
|
|
4
|
+
xAxis?: number;
|
|
5
|
+
yAxis?: number;
|
|
6
|
+
}
|
|
7
|
+
interface VisualResponseDescription {
|
|
8
|
+
componentProperty: string;
|
|
9
|
+
states: string[];
|
|
10
|
+
valueNodeProperty: string;
|
|
11
|
+
valueNodeName: string;
|
|
12
|
+
minNodeName?: string;
|
|
13
|
+
maxNodeName?: string;
|
|
14
|
+
}
|
|
15
|
+
declare type VisualResponses = Record<string, VisualResponseDescription>;
|
|
16
|
+
interface ComponentDescription {
|
|
17
|
+
type: string;
|
|
18
|
+
gamepadIndices: GamepadIndices;
|
|
19
|
+
rootNodeName: string;
|
|
20
|
+
visualResponses: VisualResponses;
|
|
21
|
+
touchPointNodeName?: string;
|
|
22
|
+
}
|
|
23
|
+
interface Components {
|
|
24
|
+
[componentKey: string]: ComponentDescription;
|
|
25
|
+
}
|
|
26
|
+
interface LayoutDescription {
|
|
27
|
+
selectComponentId: string;
|
|
28
|
+
components: Components;
|
|
29
|
+
gamepadMapping: string;
|
|
30
|
+
rootNodeName: string;
|
|
31
|
+
assetPath: string;
|
|
32
|
+
}
|
|
33
|
+
declare type Layouts = Partial<Record<XRHandedness, LayoutDescription>>;
|
|
34
|
+
export interface Profile {
|
|
35
|
+
profileId: string;
|
|
36
|
+
fallbackProfileIds: string[];
|
|
37
|
+
layouts: Layouts;
|
|
38
|
+
}
|
|
39
|
+
interface ProfilesList {
|
|
40
|
+
[profileId: string]: {
|
|
41
|
+
path: string;
|
|
42
|
+
deprecated?: boolean;
|
|
43
|
+
} | undefined;
|
|
44
|
+
}
|
|
45
|
+
declare const MotionControllerConstants: {
|
|
46
|
+
Handedness: Readonly<{
|
|
47
|
+
NONE: string;
|
|
48
|
+
LEFT: string;
|
|
49
|
+
RIGHT: string;
|
|
50
|
+
}>;
|
|
51
|
+
ComponentState: Readonly<{
|
|
52
|
+
DEFAULT: string;
|
|
53
|
+
TOUCHED: string;
|
|
54
|
+
PRESSED: string;
|
|
55
|
+
}>;
|
|
56
|
+
ComponentProperty: Readonly<{
|
|
57
|
+
BUTTON: string;
|
|
58
|
+
X_AXIS: string;
|
|
59
|
+
Y_AXIS: string;
|
|
60
|
+
STATE: string;
|
|
61
|
+
}>;
|
|
62
|
+
ComponentType: Readonly<{
|
|
63
|
+
TRIGGER: string;
|
|
64
|
+
SQUEEZE: string;
|
|
65
|
+
TOUCHPAD: string;
|
|
66
|
+
THUMBSTICK: string;
|
|
67
|
+
BUTTON: string;
|
|
68
|
+
}>;
|
|
69
|
+
ButtonTouchThreshold: number;
|
|
70
|
+
AxisTouchThreshold: number;
|
|
71
|
+
VisualResponseProperty: Readonly<{
|
|
72
|
+
TRANSFORM: string;
|
|
73
|
+
VISIBILITY: string;
|
|
74
|
+
}>;
|
|
75
|
+
};
|
|
76
|
+
declare function fetchProfilesList(basePath: string): Promise<ProfilesList>;
|
|
77
|
+
declare function fetchProfile(xrInputSource: XRInputSource, basePath: string, defaultProfile?: string | null, getAssetPath?: boolean): Promise<{
|
|
78
|
+
profile: Profile;
|
|
79
|
+
assetPath: string | undefined;
|
|
80
|
+
}>;
|
|
81
|
+
declare class VisualResponse implements VisualResponseDescription {
|
|
82
|
+
value: number | boolean;
|
|
83
|
+
componentProperty: string;
|
|
84
|
+
states: string[];
|
|
85
|
+
valueNodeName: string;
|
|
86
|
+
valueNodeProperty: string;
|
|
87
|
+
minNodeName?: string;
|
|
88
|
+
maxNodeName?: string;
|
|
89
|
+
valueNode: Object3D | undefined;
|
|
90
|
+
minNode: Object3D | undefined;
|
|
91
|
+
maxNode: Object3D | undefined;
|
|
92
|
+
constructor(visualResponseDescription: VisualResponseDescription);
|
|
93
|
+
updateFromComponent({ xAxis, yAxis, button, state, }: {
|
|
94
|
+
xAxis?: number;
|
|
95
|
+
yAxis?: number;
|
|
96
|
+
button?: number;
|
|
97
|
+
state: string;
|
|
98
|
+
}): void;
|
|
99
|
+
}
|
|
100
|
+
declare class Component implements ComponentDescription {
|
|
101
|
+
id: string;
|
|
102
|
+
values: {
|
|
103
|
+
state: string;
|
|
104
|
+
button: number | undefined;
|
|
105
|
+
xAxis: number | undefined;
|
|
106
|
+
yAxis: number | undefined;
|
|
107
|
+
};
|
|
108
|
+
type: string;
|
|
109
|
+
gamepadIndices: GamepadIndices;
|
|
110
|
+
rootNodeName: string;
|
|
111
|
+
visualResponses: Record<string, VisualResponse>;
|
|
112
|
+
touchPointNodeName?: string | undefined;
|
|
113
|
+
touchPointNode?: Object3D;
|
|
114
|
+
constructor(componentId: string, componentDescription: ComponentDescription);
|
|
115
|
+
get data(): {
|
|
116
|
+
id: Component['id'];
|
|
117
|
+
} & Component['values'];
|
|
118
|
+
updateFromGamepad(gamepad: XRGamepad): void;
|
|
119
|
+
}
|
|
120
|
+
declare class MotionController {
|
|
121
|
+
xrInputSource: XRInputSource;
|
|
122
|
+
assetUrl: string;
|
|
123
|
+
layoutDescription: LayoutDescription;
|
|
124
|
+
id: string;
|
|
125
|
+
components: Record<string, Component>;
|
|
126
|
+
constructor(xrInputSource: XRInputSource, profile: Profile, assetUrl: string);
|
|
127
|
+
get gripSpace(): XRInputSource['gripSpace'];
|
|
128
|
+
get targetRaySpace(): XRInputSource['targetRaySpace'];
|
|
129
|
+
get data(): Array<Component['data']>;
|
|
130
|
+
updateFromGamepad(): void;
|
|
131
|
+
}
|
|
132
|
+
export { MotionControllerConstants, MotionController, fetchProfile, fetchProfilesList };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @webxr-input-profiles/motion-controllers 1.0.0 https://github.com/immersive-web/webxr-input-profiles
|
|
3
5
|
*/
|
|
@@ -69,7 +71,7 @@ async function fetchProfile(xrInputSource, basePath, defaultProfile = null, getA
|
|
|
69
71
|
|
|
70
72
|
const supportedProfilesList = await fetchProfilesList(basePath); // Find the relative path to the first requested profile that is recognized
|
|
71
73
|
|
|
72
|
-
let match;
|
|
74
|
+
let match = undefined;
|
|
73
75
|
xrInputSource.profiles.some(profileId => {
|
|
74
76
|
const supportedProfile = supportedProfilesList[profileId];
|
|
75
77
|
|
|
@@ -103,7 +105,7 @@ async function fetchProfile(xrInputSource, basePath, defaultProfile = null, getA
|
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
const profile = await fetchJsonFile(match.profilePath);
|
|
106
|
-
let assetPath;
|
|
108
|
+
let assetPath = undefined;
|
|
107
109
|
|
|
108
110
|
if (getAssetPath) {
|
|
109
111
|
let layout;
|
|
@@ -142,8 +144,8 @@ const defaultComponentValues = {
|
|
|
142
144
|
* API) to the range 0 to 1 (for interpolation). Also caps the X, Y values to be bounded within
|
|
143
145
|
* a circle. This ensures that thumbsticks are not animated outside the bounds of their physical
|
|
144
146
|
* range of motion and touchpads do not report touch locations off their physical bounds.
|
|
145
|
-
* @param {number} x The original x coordinate in the range -1 to 1
|
|
146
|
-
* @param {number} y The original y coordinate in the range -1 to 1
|
|
147
|
+
* @param {number | undefined} x The original x coordinate in the range -1 to 1
|
|
148
|
+
* @param {number | undefined} y The original y coordinate in the range -1 to 1
|
|
147
149
|
*/
|
|
148
150
|
|
|
149
151
|
function normalizeAxes(x = 0, y = 0) {
|
|
@@ -179,6 +181,26 @@ function normalizeAxes(x = 0, y = 0) {
|
|
|
179
181
|
|
|
180
182
|
class VisualResponse {
|
|
181
183
|
constructor(visualResponseDescription) {
|
|
184
|
+
_defineProperty(this, "value", void 0);
|
|
185
|
+
|
|
186
|
+
_defineProperty(this, "componentProperty", void 0);
|
|
187
|
+
|
|
188
|
+
_defineProperty(this, "states", void 0);
|
|
189
|
+
|
|
190
|
+
_defineProperty(this, "valueNodeName", void 0);
|
|
191
|
+
|
|
192
|
+
_defineProperty(this, "valueNodeProperty", void 0);
|
|
193
|
+
|
|
194
|
+
_defineProperty(this, "minNodeName", void 0);
|
|
195
|
+
|
|
196
|
+
_defineProperty(this, "maxNodeName", void 0);
|
|
197
|
+
|
|
198
|
+
_defineProperty(this, "valueNode", void 0);
|
|
199
|
+
|
|
200
|
+
_defineProperty(this, "minNode", void 0);
|
|
201
|
+
|
|
202
|
+
_defineProperty(this, "maxNode", void 0);
|
|
203
|
+
|
|
182
204
|
this.componentProperty = visualResponseDescription.componentProperty;
|
|
183
205
|
this.states = visualResponseDescription.states;
|
|
184
206
|
this.valueNodeName = visualResponseDescription.valueNodeName;
|
|
@@ -196,9 +218,9 @@ class VisualResponse {
|
|
|
196
218
|
/**
|
|
197
219
|
* Computes the visual response's interpolation weight based on component state
|
|
198
220
|
* @param {Object} componentValues - The component from which to update
|
|
199
|
-
* @param {number} xAxis - The reported X axis value of the component
|
|
200
|
-
* @param {number} yAxis - The reported Y axis value of the component
|
|
201
|
-
* @param {number} button - The reported value of the component's button
|
|
221
|
+
* @param {number | undefined} xAxis - The reported X axis value of the component
|
|
222
|
+
* @param {number | undefined} yAxis - The reported Y axis value of the component
|
|
223
|
+
* @param {number | undefined} button - The reported value of the component's button
|
|
202
224
|
* @param {string} state - The component's active state
|
|
203
225
|
*/
|
|
204
226
|
|
|
@@ -224,7 +246,7 @@ class VisualResponse {
|
|
|
224
246
|
break;
|
|
225
247
|
|
|
226
248
|
case MotionControllerConstants.ComponentProperty.BUTTON:
|
|
227
|
-
this.value = this.states.includes(state) ? button : 0;
|
|
249
|
+
this.value = this.states.includes(state) && button ? button : 0;
|
|
228
250
|
break;
|
|
229
251
|
|
|
230
252
|
case MotionControllerConstants.ComponentProperty.STATE:
|
|
@@ -245,10 +267,26 @@ class VisualResponse {
|
|
|
245
267
|
|
|
246
268
|
class Component {
|
|
247
269
|
/**
|
|
248
|
-
* @param {
|
|
249
|
-
* @param {
|
|
270
|
+
* @param {string} componentId - Id of the component
|
|
271
|
+
* @param {InputProfileComponent} componentDescription - Description of the component to be created
|
|
250
272
|
*/
|
|
251
273
|
constructor(componentId, componentDescription) {
|
|
274
|
+
_defineProperty(this, "id", void 0);
|
|
275
|
+
|
|
276
|
+
_defineProperty(this, "values", void 0);
|
|
277
|
+
|
|
278
|
+
_defineProperty(this, "type", void 0);
|
|
279
|
+
|
|
280
|
+
_defineProperty(this, "gamepadIndices", void 0);
|
|
281
|
+
|
|
282
|
+
_defineProperty(this, "rootNodeName", void 0);
|
|
283
|
+
|
|
284
|
+
_defineProperty(this, "visualResponses", void 0);
|
|
285
|
+
|
|
286
|
+
_defineProperty(this, "touchPointNodeName", void 0);
|
|
287
|
+
|
|
288
|
+
_defineProperty(this, "touchPointNode", void 0);
|
|
289
|
+
|
|
252
290
|
if (!componentId || !componentDescription || !componentDescription.visualResponses || !componentDescription.gamepadIndices || Object.keys(componentDescription.gamepadIndices).length === 0) {
|
|
253
291
|
throw new Error('Invalid arguments supplied');
|
|
254
292
|
}
|
|
@@ -341,11 +379,21 @@ class Component {
|
|
|
341
379
|
|
|
342
380
|
class MotionController {
|
|
343
381
|
/**
|
|
344
|
-
* @param {
|
|
345
|
-
* @param {
|
|
346
|
-
* @param {
|
|
382
|
+
* @param {XRInputSource} xrInputSource - The XRInputSource to build the MotionController around
|
|
383
|
+
* @param {Profile} profile - The best matched profile description for the supplied xrInputSource
|
|
384
|
+
* @param {string} assetUrl
|
|
347
385
|
*/
|
|
348
386
|
constructor(xrInputSource, profile, assetUrl) {
|
|
387
|
+
_defineProperty(this, "xrInputSource", void 0);
|
|
388
|
+
|
|
389
|
+
_defineProperty(this, "assetUrl", void 0);
|
|
390
|
+
|
|
391
|
+
_defineProperty(this, "layoutDescription", void 0);
|
|
392
|
+
|
|
393
|
+
_defineProperty(this, "id", void 0);
|
|
394
|
+
|
|
395
|
+
_defineProperty(this, "components", void 0);
|
|
396
|
+
|
|
349
397
|
if (!xrInputSource) {
|
|
350
398
|
throw new Error('No xrInputSource supplied');
|
|
351
399
|
}
|
|
@@ -354,6 +402,10 @@ class MotionController {
|
|
|
354
402
|
throw new Error('No profile supplied');
|
|
355
403
|
}
|
|
356
404
|
|
|
405
|
+
if (!profile.layouts[xrInputSource.handedness]) {
|
|
406
|
+
throw new Error('No layout for ' + xrInputSource.handedness + ' handedness');
|
|
407
|
+
}
|
|
408
|
+
|
|
357
409
|
this.xrInputSource = xrInputSource;
|
|
358
410
|
this.assetUrl = assetUrl;
|
|
359
411
|
this.id = profile.profileId; // Build child components as described in the profile description
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/defineProperty"),o=require("three"),t=require("../loaders/GLTFLoader.cjs.js"),n=require("../libs/MotionControllers.cjs.js");function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var s=r(e);const a=(e,t)=>{t.traverse((t=>{t instanceof o.Mesh&&"envMap"in t.material&&(t.material.envMap=e,t.material.needsUpdate=!0)}))};class i extends o.Object3D{constructor(){super(),s.default(this,"envMap",void 0),s.default(this,"motionController",void 0),this.motionController=null,this.envMap=null}setEnvironmentMap(e){return this.envMap==e||(this.envMap=e,a(this.envMap,this)),this}updateMatrixWorld(e){super.updateMatrixWorld(e),this.motionController&&(this.motionController.updateFromGamepad(),Object.values(this.motionController.components).forEach((e=>{Object.values(e.visualResponses).forEach((e=>{const{valueNode:o,minNode:t,maxNode:r,value:s,valueNodeProperty:a}=e;o&&(a===n.MotionControllerConstants.VisualResponseProperty.VISIBILITY&&"boolean"==typeof s?o.visible=s:a===n.MotionControllerConstants.VisualResponseProperty.TRANSFORM&&t&&r&&"number"==typeof s&&(o.quaternion.slerpQuaternions(t.quaternion,r.quaternion,s),o.position.lerpVectors(t.position,r.position,s)))}))})))}}function l(e,t){!function(e,t){Object.values(e.components).forEach((e=>{const{type:r,touchPointNodeName:s,visualResponses:a}=e;if(r===n.MotionControllerConstants.ComponentType.TOUCHPAD&&s)if(e.touchPointNode=t.getObjectByName(s),e.touchPointNode){const t=new o.SphereGeometry(.001),n=new o.MeshBasicMaterial({color:255}),r=new o.Mesh(t,n);e.touchPointNode.add(r)}else console.warn(`Could not find touch dot, ${e.touchPointNodeName}, in touchpad component ${e.id}`);Object.values(a).forEach((e=>{const{valueNodeName:o,minNodeName:r,maxNodeName:s,valueNodeProperty:a}=e;if(a===n.MotionControllerConstants.VisualResponseProperty.TRANSFORM&&r&&s){if(e.minNode=t.getObjectByName(r),e.maxNode=t.getObjectByName(s),!e.minNode)return void console.warn(`Could not find ${r} in the model`);if(!e.maxNode)return void console.warn(`Could not find ${s} in the model`)}e.valueNode=t.getObjectByName(o),e.valueNode||console.warn(`Could not find ${o} in the model`)}))}))}(e.motionController,t),e.envMap&&a(e.envMap,t),e.add(t)}exports.XRControllerModelFactory=class{constructor(e=null){s.default(this,"gltfLoader",void 0),s.default(this,"path",void 0),s.default(this,"_assetCache",void 0),this.gltfLoader=e,this.path="https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles",this._assetCache={},this.gltfLoader||(this.gltfLoader=new t.GLTFLoader)}createControllerModel(e){const o=new i;let t=null;const r=e=>{const r=e.data;"tracked-pointer"===r.targetRayMode&&r.gamepad&&n.fetchProfile(r,this.path,"generic-trigger").then((({profile:e,assetPath:s})=>{if(!s)throw new Error("no asset path");o.motionController=new n.MotionController(r,e,s);const a=o.motionController.assetUrl,i=this._assetCache[a];if(i)t=i.scene.clone(),l(o,t);else{if(!this.gltfLoader)throw new Error("GLTFLoader not set.");this.gltfLoader.setPath(""),this.gltfLoader.load(o.motionController.assetUrl,(e=>{o.motionController?(this._assetCache[a]=e,t=e.scene.clone(),l(o,t)):console.warn("motionController gone while gltf load, bailing...")}),null,(()=>{throw new Error(`Asset ${a} missing or malformed.`)}))}})).catch((e=>{console.warn(e)}))};e.addEventListener("connected",r);const s=()=>{e.removeEventListener("connected",r),e.removeEventListener("disconnected",s),o.motionController=null,t&&o.remove(t),t=null};return e.addEventListener("disconnected",s),o}};
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { Object3D } from 'three';
|
|
2
|
+
import type { Texture, Group } from 'three';
|
|
3
3
|
import { GLTFLoader } from '../loaders/GLTFLoader';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { MotionController } from '../libs/MotionControllers';
|
|
5
|
+
declare class XRControllerModel extends Object3D {
|
|
6
|
+
envMap: Texture | null;
|
|
7
|
+
motionController: MotionController | null;
|
|
6
8
|
constructor();
|
|
7
|
-
|
|
8
|
-
motionController: any;
|
|
9
|
-
|
|
10
9
|
setEnvironmentMap(envMap: Texture): XRControllerModel;
|
|
10
|
+
updateMatrixWorld(force: boolean): void;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
constructor(gltfLoader?: GLTFLoader);
|
|
15
|
-
gltfLoader: GLTFLoader | null;
|
|
12
|
+
declare class XRControllerModelFactory {
|
|
13
|
+
gltfLoader: GLTFLoader;
|
|
16
14
|
path: string;
|
|
17
|
-
|
|
15
|
+
private _assetCache;
|
|
16
|
+
constructor(gltfLoader?: GLTFLoader);
|
|
18
17
|
createControllerModel(controller: Group): XRControllerModel;
|
|
19
18
|
}
|
|
19
|
+
export { XRControllerModelFactory };
|
|
@@ -1,13 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
|
|
2
|
+
import { Object3D, Mesh, SphereGeometry, MeshBasicMaterial } from 'three';
|
|
2
3
|
import { GLTFLoader } from '../loaders/GLTFLoader.js';
|
|
3
|
-
import { fetchProfile, MotionController
|
|
4
|
+
import { MotionControllerConstants, fetchProfile, MotionController } from '../libs/MotionControllers.js';
|
|
4
5
|
|
|
5
6
|
const DEFAULT_PROFILES_PATH = 'https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles';
|
|
6
7
|
const DEFAULT_PROFILE = 'generic-trigger';
|
|
7
8
|
|
|
9
|
+
const applyEnvironmentMap = (envMap, obj) => {
|
|
10
|
+
obj.traverse(child => {
|
|
11
|
+
if (child instanceof Mesh && 'envMap' in child.material) {
|
|
12
|
+
child.material.envMap = envMap;
|
|
13
|
+
child.material.needsUpdate = true;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
|
|
8
18
|
class XRControllerModel extends Object3D {
|
|
9
19
|
constructor() {
|
|
10
20
|
super();
|
|
21
|
+
|
|
22
|
+
_defineProperty(this, "envMap", void 0);
|
|
23
|
+
|
|
24
|
+
_defineProperty(this, "motionController", void 0);
|
|
25
|
+
|
|
11
26
|
this.motionController = null;
|
|
12
27
|
this.envMap = null;
|
|
13
28
|
}
|
|
@@ -18,12 +33,7 @@ class XRControllerModel extends Object3D {
|
|
|
18
33
|
}
|
|
19
34
|
|
|
20
35
|
this.envMap = envMap;
|
|
21
|
-
this.
|
|
22
|
-
if (child.isMesh) {
|
|
23
|
-
child.material.envMap = this.envMap;
|
|
24
|
-
child.material.needsUpdate = true;
|
|
25
|
-
}
|
|
26
|
-
});
|
|
36
|
+
applyEnvironmentMap(this.envMap, this);
|
|
27
37
|
return this;
|
|
28
38
|
}
|
|
29
39
|
/**
|
|
@@ -52,9 +62,9 @@ class XRControllerModel extends Object3D {
|
|
|
52
62
|
|
|
53
63
|
if (!valueNode) return; // Calculate the new properties based on the weight supplied
|
|
54
64
|
|
|
55
|
-
if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.VISIBILITY) {
|
|
65
|
+
if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.VISIBILITY && typeof value === 'boolean') {
|
|
56
66
|
valueNode.visible = value;
|
|
57
|
-
} else if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM) {
|
|
67
|
+
} else if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM && minNode && maxNode && typeof value === 'number') {
|
|
58
68
|
valueNode.quaternion.slerpQuaternions(minNode.quaternion, maxNode.quaternion, value);
|
|
59
69
|
valueNode.position.lerpVectors(minNode.position, maxNode.position, value);
|
|
60
70
|
}
|
|
@@ -79,7 +89,7 @@ function findNodes(motionController, scene) {
|
|
|
79
89
|
visualResponses
|
|
80
90
|
} = component;
|
|
81
91
|
|
|
82
|
-
if (type === MotionControllerConstants.ComponentType.TOUCHPAD) {
|
|
92
|
+
if (type === MotionControllerConstants.ComponentType.TOUCHPAD && touchPointNodeName) {
|
|
83
93
|
component.touchPointNode = scene.getObjectByName(touchPointNodeName);
|
|
84
94
|
|
|
85
95
|
if (component.touchPointNode) {
|
|
@@ -104,7 +114,7 @@ function findNodes(motionController, scene) {
|
|
|
104
114
|
valueNodeProperty
|
|
105
115
|
} = visualResponse; // If animating a transform, find the two nodes to be interpolated between.
|
|
106
116
|
|
|
107
|
-
if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM) {
|
|
117
|
+
if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM && minNodeName && maxNodeName) {
|
|
108
118
|
visualResponse.minNode = scene.getObjectByName(minNodeName);
|
|
109
119
|
visualResponse.maxNode = scene.getObjectByName(maxNodeName); // If the extents cannot be found, skip this animation
|
|
110
120
|
|
|
@@ -134,12 +144,7 @@ function addAssetSceneToControllerModel(controllerModel, scene) {
|
|
|
134
144
|
findNodes(controllerModel.motionController, scene); // Apply any environment map that the mesh already has set.
|
|
135
145
|
|
|
136
146
|
if (controllerModel.envMap) {
|
|
137
|
-
|
|
138
|
-
if (child.isMesh) {
|
|
139
|
-
child.material.envMap = controllerModel.envMap;
|
|
140
|
-
child.material.needsUpdate = true;
|
|
141
|
-
}
|
|
142
|
-
});
|
|
147
|
+
applyEnvironmentMap(controllerModel.envMap, scene);
|
|
143
148
|
} // Add the glTF scene to the controllerModel.
|
|
144
149
|
|
|
145
150
|
|
|
@@ -148,6 +153,12 @@ function addAssetSceneToControllerModel(controllerModel, scene) {
|
|
|
148
153
|
|
|
149
154
|
class XRControllerModelFactory {
|
|
150
155
|
constructor(gltfLoader = null) {
|
|
156
|
+
_defineProperty(this, "gltfLoader", void 0);
|
|
157
|
+
|
|
158
|
+
_defineProperty(this, "path", void 0);
|
|
159
|
+
|
|
160
|
+
_defineProperty(this, "_assetCache", void 0);
|
|
161
|
+
|
|
151
162
|
this.gltfLoader = gltfLoader;
|
|
152
163
|
this.path = DEFAULT_PROFILES_PATH;
|
|
153
164
|
this._assetCache = {}; // If a GLTFLoader wasn't supplied to the constructor create a new one.
|
|
@@ -160,15 +171,21 @@ class XRControllerModelFactory {
|
|
|
160
171
|
createControllerModel(controller) {
|
|
161
172
|
const controllerModel = new XRControllerModel();
|
|
162
173
|
let scene = null;
|
|
163
|
-
|
|
174
|
+
|
|
175
|
+
const onConnected = event => {
|
|
164
176
|
const xrInputSource = event.data;
|
|
165
177
|
if (xrInputSource.targetRayMode !== 'tracked-pointer' || !xrInputSource.gamepad) return;
|
|
166
178
|
fetchProfile(xrInputSource, this.path, DEFAULT_PROFILE).then(({
|
|
167
179
|
profile,
|
|
168
180
|
assetPath
|
|
169
181
|
}) => {
|
|
182
|
+
if (!assetPath) {
|
|
183
|
+
throw new Error('no asset path');
|
|
184
|
+
}
|
|
185
|
+
|
|
170
186
|
controllerModel.motionController = new MotionController(xrInputSource, profile, assetPath);
|
|
171
|
-
const
|
|
187
|
+
const assetUrl = controllerModel.motionController.assetUrl;
|
|
188
|
+
const cachedAsset = this._assetCache[assetUrl];
|
|
172
189
|
|
|
173
190
|
if (cachedAsset) {
|
|
174
191
|
scene = cachedAsset.scene.clone();
|
|
@@ -180,22 +197,38 @@ class XRControllerModelFactory {
|
|
|
180
197
|
|
|
181
198
|
this.gltfLoader.setPath('');
|
|
182
199
|
this.gltfLoader.load(controllerModel.motionController.assetUrl, asset => {
|
|
183
|
-
|
|
200
|
+
if (!controllerModel.motionController) {
|
|
201
|
+
console.warn('motionController gone while gltf load, bailing...');
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
this._assetCache[assetUrl] = asset;
|
|
184
206
|
scene = asset.scene.clone();
|
|
185
207
|
addAssetSceneToControllerModel(controllerModel, scene);
|
|
186
208
|
}, null, () => {
|
|
187
|
-
throw new Error(`Asset ${
|
|
209
|
+
throw new Error(`Asset ${assetUrl} missing or malformed.`);
|
|
188
210
|
});
|
|
189
211
|
}
|
|
190
212
|
}).catch(err => {
|
|
191
213
|
console.warn(err);
|
|
192
214
|
});
|
|
193
|
-
}
|
|
194
|
-
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
controller.addEventListener('connected', onConnected);
|
|
218
|
+
|
|
219
|
+
const onDisconnected = () => {
|
|
220
|
+
controller.removeEventListener('connected', onConnected);
|
|
221
|
+
controller.removeEventListener('disconnected', onDisconnected);
|
|
195
222
|
controllerModel.motionController = null;
|
|
196
|
-
|
|
223
|
+
|
|
224
|
+
if (scene) {
|
|
225
|
+
controllerModel.remove(scene);
|
|
226
|
+
}
|
|
227
|
+
|
|
197
228
|
scene = null;
|
|
198
|
-
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
controller.addEventListener('disconnected', onDisconnected);
|
|
199
232
|
return controllerModel;
|
|
200
233
|
}
|
|
201
234
|
|