three-stdlib 2.20.5 → 2.21.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +46 -21
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 l 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 i(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 l;let t=null;return e.addEventListener("connected",(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,l=this._assetCache[a];if(l)t=l.scene.clone(),i(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(),i(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("disconnected",(()=>{o.motionController=null,t&&o.remove(t),t=null})),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
4
|
import { fetchProfile, MotionController, MotionControllerConstants } 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.
|
@@ -167,8 +178,13 @@ class XRControllerModelFactory {
|
|
167
178
|
profile,
|
168
179
|
assetPath
|
169
180
|
}) => {
|
181
|
+
if (!assetPath) {
|
182
|
+
throw new Error('no asset path');
|
183
|
+
}
|
184
|
+
|
170
185
|
controllerModel.motionController = new MotionController(xrInputSource, profile, assetPath);
|
171
|
-
const
|
186
|
+
const assetUrl = controllerModel.motionController.assetUrl;
|
187
|
+
const cachedAsset = this._assetCache[assetUrl];
|
172
188
|
|
173
189
|
if (cachedAsset) {
|
174
190
|
scene = cachedAsset.scene.clone();
|
@@ -180,11 +196,16 @@ class XRControllerModelFactory {
|
|
180
196
|
|
181
197
|
this.gltfLoader.setPath('');
|
182
198
|
this.gltfLoader.load(controllerModel.motionController.assetUrl, asset => {
|
183
|
-
|
199
|
+
if (!controllerModel.motionController) {
|
200
|
+
console.warn('motionController gone while gltf load, bailing...');
|
201
|
+
return;
|
202
|
+
}
|
203
|
+
|
204
|
+
this._assetCache[assetUrl] = asset;
|
184
205
|
scene = asset.scene.clone();
|
185
206
|
addAssetSceneToControllerModel(controllerModel, scene);
|
186
207
|
}, null, () => {
|
187
|
-
throw new Error(`Asset ${
|
208
|
+
throw new Error(`Asset ${assetUrl} missing or malformed.`);
|
188
209
|
});
|
189
210
|
}
|
190
211
|
}).catch(err => {
|
@@ -193,7 +214,11 @@ class XRControllerModelFactory {
|
|
193
214
|
});
|
194
215
|
controller.addEventListener('disconnected', () => {
|
195
216
|
controllerModel.motionController = null;
|
196
|
-
|
217
|
+
|
218
|
+
if (scene) {
|
219
|
+
controllerModel.remove(scene);
|
220
|
+
}
|
221
|
+
|
197
222
|
scene = null;
|
198
223
|
});
|
199
224
|
return controllerModel;
|