three-stdlib 2.8.4 → 2.8.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,248 @@
1
+ import * as THREE from 'three';
2
+
3
+ const PINCH_MAX = 0.05;
4
+ const PINCH_THRESHOLD = 0.02;
5
+ const PINCH_MIN = 0.01;
6
+ const POINTER_ADVANCE_MAX = 0.02;
7
+ const POINTER_OPACITY_MAX = 1;
8
+ const POINTER_OPACITY_MIN = 0.4;
9
+ const POINTER_FRONT_RADIUS = 0.002;
10
+ const POINTER_REAR_RADIUS = 0.01;
11
+ const POINTER_REAR_RADIUS_MIN = 0.003;
12
+ const POINTER_LENGTH = 0.035;
13
+ const POINTER_SEGMENTS = 16;
14
+ const POINTER_RINGS = 12;
15
+ const POINTER_HEMISPHERE_ANGLE = 110;
16
+ const YAXIS = new THREE.Vector3(0, 1, 0);
17
+ const ZAXIS = new THREE.Vector3(0, 0, 1);
18
+ const CURSOR_RADIUS = 0.02;
19
+ const CURSOR_MAX_DISTANCE = 1.5;
20
+
21
+ class OculusHandPointerModel extends THREE.Object3D {
22
+ constructor(hand, controller) {
23
+ super();
24
+ this.hand = hand;
25
+ this.controller = controller;
26
+ this.motionController = null;
27
+ this.envMap = null;
28
+ this.mesh = null;
29
+ this.pointerGeometry = null;
30
+ this.pointerMesh = null;
31
+ this.pointerObject = null;
32
+ this.pinched = false;
33
+ this.attached = false;
34
+ this.cursorObject = null;
35
+ this.raycaster = null;
36
+ hand.addEventListener('connected', event => {
37
+ const xrInputSource = event.data;
38
+
39
+ if (xrInputSource.hand) {
40
+ this.visible = true;
41
+ this.xrInputSource = xrInputSource;
42
+ this.createPointer();
43
+ }
44
+ });
45
+ }
46
+
47
+ _drawVerticesRing(vertices, baseVector, ringIndex) {
48
+ const segmentVector = baseVector.clone();
49
+
50
+ for (var i = 0; i < POINTER_SEGMENTS; i++) {
51
+ segmentVector.applyAxisAngle(ZAXIS, Math.PI * 2 / POINTER_SEGMENTS);
52
+ const vid = ringIndex * POINTER_SEGMENTS + i;
53
+ vertices[3 * vid] = segmentVector.x;
54
+ vertices[3 * vid + 1] = segmentVector.y;
55
+ vertices[3 * vid + 2] = segmentVector.z;
56
+ }
57
+ }
58
+
59
+ _updatePointerVertices(rearRadius) {
60
+ const vertices = this.pointerGeometry.attributes.position.array; // first ring for front face
61
+
62
+ const frontFaceBase = new THREE.Vector3(POINTER_FRONT_RADIUS, 0, -1 * (POINTER_LENGTH - rearRadius));
63
+
64
+ this._drawVerticesRing(vertices, frontFaceBase, 0); // rings for rear hemisphere
65
+
66
+
67
+ const rearBase = new THREE.Vector3(Math.sin(Math.PI * POINTER_HEMISPHERE_ANGLE / 180) * rearRadius, Math.cos(Math.PI * POINTER_HEMISPHERE_ANGLE / 180) * rearRadius, 0);
68
+
69
+ for (var i = 0; i < POINTER_RINGS; i++) {
70
+ this._drawVerticesRing(vertices, rearBase, i + 1);
71
+
72
+ rearBase.applyAxisAngle(YAXIS, Math.PI * POINTER_HEMISPHERE_ANGLE / 180 / (POINTER_RINGS * -2));
73
+ } // front and rear face center vertices
74
+
75
+
76
+ const frontCenterIndex = POINTER_SEGMENTS * (1 + POINTER_RINGS);
77
+ const rearCenterIndex = POINTER_SEGMENTS * (1 + POINTER_RINGS) + 1;
78
+ const frontCenter = new THREE.Vector3(0, 0, -1 * (POINTER_LENGTH - rearRadius));
79
+ vertices[frontCenterIndex * 3] = frontCenter.x;
80
+ vertices[frontCenterIndex * 3 + 1] = frontCenter.y;
81
+ vertices[frontCenterIndex * 3 + 2] = frontCenter.z;
82
+ const rearCenter = new THREE.Vector3(0, 0, rearRadius);
83
+ vertices[rearCenterIndex * 3] = rearCenter.x;
84
+ vertices[rearCenterIndex * 3 + 1] = rearCenter.y;
85
+ vertices[rearCenterIndex * 3 + 2] = rearCenter.z;
86
+ this.pointerGeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)); // verticesNeedUpdate = true;
87
+ }
88
+
89
+ createPointer() {
90
+ var i, j;
91
+ const vertices = new Array(((POINTER_RINGS + 1) * POINTER_SEGMENTS + 2) * 3).fill(0); // const vertices = [];
92
+
93
+ const indices = [];
94
+ this.pointerGeometry = new THREE.BufferGeometry();
95
+ this.pointerGeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
96
+
97
+ this._updatePointerVertices(POINTER_REAR_RADIUS); // construct faces to connect rings
98
+
99
+
100
+ for (i = 0; i < POINTER_RINGS; i++) {
101
+ for (j = 0; j < POINTER_SEGMENTS - 1; j++) {
102
+ indices.push(i * POINTER_SEGMENTS + j, i * POINTER_SEGMENTS + j + 1, (i + 1) * POINTER_SEGMENTS + j);
103
+ indices.push(i * POINTER_SEGMENTS + j + 1, (i + 1) * POINTER_SEGMENTS + j + 1, (i + 1) * POINTER_SEGMENTS + j);
104
+ }
105
+
106
+ indices.push((i + 1) * POINTER_SEGMENTS - 1, i * POINTER_SEGMENTS, (i + 2) * POINTER_SEGMENTS - 1);
107
+ indices.push(i * POINTER_SEGMENTS, (i + 1) * POINTER_SEGMENTS, (i + 2) * POINTER_SEGMENTS - 1);
108
+ } // construct front and rear face
109
+
110
+
111
+ const frontCenterIndex = POINTER_SEGMENTS * (1 + POINTER_RINGS);
112
+ const rearCenterIndex = POINTER_SEGMENTS * (1 + POINTER_RINGS) + 1;
113
+
114
+ for (i = 0; i < POINTER_SEGMENTS - 1; i++) {
115
+ indices.push(frontCenterIndex, i + 1, i);
116
+ indices.push(rearCenterIndex, i + POINTER_SEGMENTS * POINTER_RINGS, i + POINTER_SEGMENTS * POINTER_RINGS + 1);
117
+ }
118
+
119
+ indices.push(frontCenterIndex, 0, POINTER_SEGMENTS - 1);
120
+ indices.push(rearCenterIndex, POINTER_SEGMENTS * (POINTER_RINGS + 1) - 1, POINTER_SEGMENTS * POINTER_RINGS);
121
+ const material = new THREE.MeshBasicMaterial();
122
+ material.transparent = true;
123
+ material.opacity = POINTER_OPACITY_MIN;
124
+ this.pointerGeometry.setIndex(indices);
125
+ this.pointerMesh = new THREE.Mesh(this.pointerGeometry, material);
126
+ this.pointerMesh.position.set(0, 0, -1 * POINTER_REAR_RADIUS);
127
+ this.pointerObject = new THREE.Object3D();
128
+ this.pointerObject.add(this.pointerMesh);
129
+ this.raycaster = new THREE.Raycaster(); // create cursor
130
+
131
+ const cursorGeometry = new THREE.SphereGeometry(CURSOR_RADIUS, 10, 10);
132
+ const cursorMaterial = new THREE.MeshBasicMaterial();
133
+ cursorMaterial.transparent = true;
134
+ cursorMaterial.opacity = POINTER_OPACITY_MIN;
135
+ this.cursorObject = new THREE.Mesh(cursorGeometry, cursorMaterial);
136
+ this.pointerObject.add(this.cursorObject);
137
+ this.add(this.pointerObject);
138
+ }
139
+
140
+ _updateRaycaster() {
141
+ if (this.raycaster) {
142
+ const pointerMatrix = this.pointerObject.matrixWorld;
143
+ const tempMatrix = new THREE.Matrix4();
144
+ tempMatrix.identity().extractRotation(pointerMatrix);
145
+ this.raycaster.ray.origin.setFromMatrixPosition(pointerMatrix);
146
+ this.raycaster.ray.direction.set(0, 0, -1).applyMatrix4(tempMatrix);
147
+ }
148
+ }
149
+
150
+ _updatePointer() {
151
+ this.pointerObject.visible = this.controller.visible;
152
+ const indexTip = this.hand.joints['index-finger-tip'];
153
+ const thumbTip = this.hand.joints['thumb-tip'];
154
+ const distance = indexTip.position.distanceTo(thumbTip.position);
155
+ const position = indexTip.position.clone().add(thumbTip.position).multiplyScalar(0.5);
156
+ this.pointerObject.position.copy(position);
157
+ this.pointerObject.quaternion.copy(this.controller.quaternion);
158
+ this.pinched = distance <= PINCH_THRESHOLD;
159
+ const pinchScale = (distance - PINCH_MIN) / (PINCH_MAX - PINCH_MIN);
160
+ const focusScale = (distance - PINCH_MIN) / (PINCH_THRESHOLD - PINCH_MIN);
161
+
162
+ if (pinchScale > 1) {
163
+ this._updatePointerVertices(POINTER_REAR_RADIUS);
164
+
165
+ this.pointerMesh.position.set(0, 0, -1 * POINTER_REAR_RADIUS);
166
+ this.pointerMesh.material.opacity = POINTER_OPACITY_MIN;
167
+ } else if (pinchScale > 0) {
168
+ const rearRadius = (POINTER_REAR_RADIUS - POINTER_REAR_RADIUS_MIN) * pinchScale + POINTER_REAR_RADIUS_MIN;
169
+
170
+ this._updatePointerVertices(rearRadius);
171
+
172
+ if (focusScale < 1) {
173
+ this.pointerMesh.position.set(0, 0, -1 * rearRadius - (1 - focusScale) * POINTER_ADVANCE_MAX);
174
+ this.pointerMesh.material.opacity = POINTER_OPACITY_MIN + (1 - focusScale) * (POINTER_OPACITY_MAX - POINTER_OPACITY_MIN);
175
+ } else {
176
+ this.pointerMesh.position.set(0, 0, -1 * rearRadius);
177
+ this.pointerMesh.material.opacity = POINTER_OPACITY_MIN;
178
+ }
179
+ } else {
180
+ this._updatePointerVertices(POINTER_REAR_RADIUS_MIN);
181
+
182
+ this.pointerMesh.position.set(0, 0, -1 * POINTER_REAR_RADIUS_MIN - POINTER_ADVANCE_MAX);
183
+ this.pointerMesh.material.opacity = POINTER_OPACITY_MAX;
184
+ }
185
+
186
+ this.cursorObject.material.opacity = this.pointerMesh.material.opacity;
187
+ }
188
+
189
+ updateMatrixWorld(force) {
190
+ super.updateMatrixWorld(force);
191
+
192
+ if (this.pointerGeometry) {
193
+ this._updatePointer();
194
+
195
+ this._updateRaycaster();
196
+ }
197
+ }
198
+
199
+ isPinched() {
200
+ return this.pinched;
201
+ }
202
+
203
+ setAttached(attached) {
204
+ this.attached = attached;
205
+ }
206
+
207
+ isAttached() {
208
+ return this.attached;
209
+ }
210
+
211
+ intersectObject(object, recursive = true) {
212
+ if (this.raycaster) {
213
+ return this.raycaster.intersectObject(object, recursive);
214
+ }
215
+ }
216
+
217
+ intersectObjects(objects, recursive = true) {
218
+ if (this.raycaster) {
219
+ return this.raycaster.intersectObjects(objects, recursive);
220
+ }
221
+ }
222
+
223
+ checkIntersections(objects, recursive = false) {
224
+ if (this.raycaster && !this.attached) {
225
+ const intersections = this.raycaster.intersectObjects(objects, recursive);
226
+ const direction = new THREE.Vector3(0, 0, -1);
227
+
228
+ if (intersections.length > 0) {
229
+ const intersection = intersections[0];
230
+ const distance = intersection.distance;
231
+ this.cursorObject.position.copy(direction.multiplyScalar(distance));
232
+ } else {
233
+ this.cursorObject.position.copy(direction.multiplyScalar(CURSOR_MAX_DISTANCE));
234
+ }
235
+ }
236
+ }
237
+
238
+ setCursor(distance) {
239
+ const direction = new THREE.Vector3(0, 0, -1);
240
+
241
+ if (this.raycaster && !this.attached) {
242
+ this.cursorObject.position.copy(direction.multiplyScalar(distance));
243
+ }
244
+ }
245
+
246
+ }
247
+
248
+ export { OculusHandPointerModel };
@@ -0,0 +1 @@
1
+ "use strict";function e(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}Object.defineProperty(exports,"__esModule",{value:!0});var t=e(require("three"));exports.createText=function(e,r){const n=document.createElement("canvas"),l=n.getContext("2d");let o=null;const a=100;l.font="normal 100px Arial",o=l.measureText(e);const c=o.width;n.width=c,n.height=a,l.font="normal 100px Arial",l.textAlign="center",l.textBaseline="middle",l.fillStyle="#ffffff",l.fillText(e,c/2,50);const i=new t.Texture(n);i.needsUpdate=!0;const f=new t.MeshBasicMaterial({color:16777215,side:t.DoubleSide,map:i,transparent:!0}),s=new t.PlaneGeometry(r*c/a,r);return new t.Mesh(s,f)};
@@ -0,0 +1,3 @@
1
+ import { Mesh } from 'three';
2
+
3
+ export function createText(message: string, height: number): Mesh;
@@ -0,0 +1,32 @@
1
+ import * as THREE from 'three';
2
+
3
+ function createText(message, height) {
4
+ const canvas = document.createElement('canvas');
5
+ const context = canvas.getContext('2d');
6
+ let metrics = null;
7
+ const textHeight = 100;
8
+ context.font = 'normal ' + textHeight + 'px Arial';
9
+ metrics = context.measureText(message);
10
+ const textWidth = metrics.width;
11
+ canvas.width = textWidth;
12
+ canvas.height = textHeight;
13
+ context.font = 'normal ' + textHeight + 'px Arial';
14
+ context.textAlign = 'center';
15
+ context.textBaseline = 'middle';
16
+ context.fillStyle = '#ffffff';
17
+ context.fillText(message, textWidth / 2, textHeight / 2);
18
+ const texture = new THREE.Texture(canvas);
19
+ texture.needsUpdate = true; //var spriteAlignment = new THREE.Vector2(0,0) ;
20
+
21
+ const material = new THREE.MeshBasicMaterial({
22
+ color: 0xffffff,
23
+ side: THREE.DoubleSide,
24
+ map: texture,
25
+ transparent: true
26
+ });
27
+ const geometry = new THREE.PlaneGeometry(height * textWidth / textHeight, height);
28
+ const plane = new THREE.Mesh(geometry, material);
29
+ return plane;
30
+ }
31
+
32
+ export { createText };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});exports.VRButton=class{static createButton(e,t){t&&console.error('THREE.VRButton: The "options" parameter has been removed. Please set the reference space type via renderer.xr.setReferenceSpaceType() instead.');const n=document.createElement("button");function o(){n.style.display="",n.style.cursor="auto",n.style.left="calc(50% - 75px)",n.style.width="150px",n.onmouseenter=null,n.onmouseleave=null,n.onclick=null,n.textContent="VR NOT SUPPORTED"}function s(e){e.style.position="absolute",e.style.bottom="20px",e.style.padding="12px 6px",e.style.border="1px solid #fff",e.style.borderRadius="4px",e.style.background="rgba(0,0,0,0.1)",e.style.color="#fff",e.style.font="normal 13px sans-serif",e.style.textAlign="center",e.style.opacity="0.5",e.style.outline="none",e.style.zIndex="999"}if("xr"in navigator)return n.id="VRButton",n.style.display="none",s(n),navigator.xr.isSessionSupported("immersive-vr").then((function(t){t?function(){let t=null;async function o(o){o.addEventListener("end",s),await e.xr.setSession(o),n.textContent="EXIT VR",t=o}function s(){t.removeEventListener("end",s),n.textContent="ENTER VR",t=null}n.style.display="",n.style.cursor="pointer",n.style.left="calc(50% - 50px)",n.style.width="100px",n.textContent="ENTER VR",n.onmouseenter=function(){n.style.opacity="1.0"},n.onmouseleave=function(){n.style.opacity="0.5"},n.onclick=function(){if(null===t){const e={optionalFeatures:["local-floor","bounded-floor","hand-tracking"]};navigator.xr.requestSession("immersive-vr",e).then(o)}else t.end()}}():o()})),n;{const e=document.createElement("a");return!1===window.isSecureContext?(e.href=document.location.href.replace(/^http:/,"https:"),e.innerHTML="WEBXR NEEDS HTTPS"):(e.href="https://immersiveweb.dev/",e.innerHTML="WEBXR NOT AVAILABLE"),e.style.left="calc(50% - 90px)",e.style.width="180px",e.style.textDecoration="none",s(e),e}}};
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"));class n{static createButton(e,t){t&&console.error('THREE.VRButton: The "options" parameter has been removed. Please set the reference space type via renderer.xr.setReferenceSpaceType() instead.');const o=document.createElement("button");function s(){o.style.display="",o.style.cursor="auto",o.style.left="calc(50% - 75px)",o.style.width="150px",o.onmouseenter=null,o.onmouseleave=null,o.onclick=null,o.textContent="VR NOT SUPPORTED"}function r(e){e.style.position="absolute",e.style.bottom="20px",e.style.padding="12px 6px",e.style.border="1px solid #fff",e.style.borderRadius="4px",e.style.background="rgba(0,0,0,0.1)",e.style.color="#fff",e.style.font="normal 13px sans-serif",e.style.textAlign="center",e.style.opacity="0.5",e.style.outline="none",e.style.zIndex="999"}if("xr"in navigator)return o.id="VRButton",o.style.display="none",r(o),navigator.xr.isSessionSupported("immersive-vr").then((function(t){t?function(){let t=null;async function n(n){n.addEventListener("end",s),await e.xr.setSession(n),o.textContent="EXIT VR",t=n}function s(){t.removeEventListener("end",s),o.textContent="ENTER VR",t=null}o.style.display="",o.style.cursor="pointer",o.style.left="calc(50% - 50px)",o.style.width="100px",o.textContent="ENTER VR",o.onmouseenter=function(){o.style.opacity="1.0"},o.onmouseleave=function(){o.style.opacity="0.5"},o.onclick=function(){if(null===t){const e={optionalFeatures:["local-floor","bounded-floor","hand-tracking","layers"]};navigator.xr.requestSession("immersive-vr",e).then(n)}else t.end()}}():s(),t&&n.xrSessionIsGranted&&o.click()})),o;{const e=document.createElement("a");return!1===window.isSecureContext?(e.href=document.location.href.replace(/^http:/,"https:"),e.innerHTML="WEBXR NEEDS HTTPS"):(e.href="https://immersiveweb.dev/",e.innerHTML="WEBXR NOT AVAILABLE"),e.style.left="calc(50% - 90px)",e.style.width="180px",e.style.textDecoration="none",r(e),e}}static registerSessionGrantedListener(){"xr"in navigator&&navigator.xr.addEventListener("sessiongranted",(()=>{n.xrSessionIsGranted=!0}))}}t.default(n,"xrSessionIsGranted",!1),exports.VRButton=n;
package/webxr/VRButton.js CHANGED
@@ -1,3 +1,5 @@
1
+ import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
2
+
1
3
  class VRButton {
2
4
  static createButton(renderer, options) {
3
5
  if (options) {
@@ -50,7 +52,7 @@ class VRButton {
50
52
  // ('local' is always available for immersive sessions and doesn't need to
51
53
  // be requested separately.)
52
54
  const sessionInit = {
53
- optionalFeatures: ['local-floor', 'bounded-floor', 'hand-tracking']
55
+ optionalFeatures: ['local-floor', 'bounded-floor', 'hand-tracking', 'layers']
54
56
  };
55
57
  navigator.xr.requestSession('immersive-vr', sessionInit).then(onSessionStarted);
56
58
  } else {
@@ -95,6 +97,10 @@ class VRButton {
95
97
  stylizeElement(button);
96
98
  navigator.xr.isSessionSupported('immersive-vr').then(function (supported) {
97
99
  supported ? showEnterVR() : showWebXRNotFound();
100
+
101
+ if (supported && VRButton.xrSessionIsGranted) {
102
+ button.click();
103
+ }
98
104
  });
99
105
  return button;
100
106
  } else {
@@ -116,6 +122,16 @@ class VRButton {
116
122
  }
117
123
  }
118
124
 
125
+ static registerSessionGrantedListener() {
126
+ if ('xr' in navigator) {
127
+ navigator.xr.addEventListener('sessiongranted', () => {
128
+ VRButton.xrSessionIsGranted = true;
129
+ });
130
+ }
131
+ }
132
+
119
133
  }
120
134
 
135
+ _defineProperty(VRButton, "xrSessionIsGranted", false);
136
+
121
137
  export { VRButton };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("three"),t=require("../loaders/GLTFLoader.cjs.js"),o=require("@webxr-input-profiles/motion-controllers");function n(){e.Object3D.call(this),this.motionController=null,this.envMap=null}function r(t,n){!function(t,n){Object.values(t.components).forEach((t=>{const{type:r,touchPointNodeName:s,visualResponses:a}=t;if(r===o.Constants.ComponentType.TOUCHPAD)if(t.touchPointNode=n.getObjectByName(s),t.touchPointNode){const o=new e.SphereGeometry(.001),n=new e.MeshBasicMaterial({color:255}),r=new e.Mesh(o,n);t.touchPointNode.add(r)}else console.warn(`Could not find touch dot, ${t.touchPointNodeName}, in touchpad component ${t.id}`);Object.values(a).forEach((e=>{const{valueNodeName:t,minNodeName:r,maxNodeName:s,valueNodeProperty:a}=e;if(a===o.Constants.VisualResponseProperty.TRANSFORM){if(e.minNode=n.getObjectByName(r),e.maxNode=n.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=n.getObjectByName(t),e.valueNode||console.warn(`Could not find ${t} in the model`)}))}))}(t.motionController,n),t.envMap&&n.traverse((e=>{e.isMesh&&(e.material.envMap=t.envMap,e.material.needsUpdate=!0)})),t.add(n)}n.prototype=Object.assign(Object.create(e.Object3D.prototype),{constructor:n,setEnvironmentMap:function(e){return this.envMap==e||(this.envMap=e,this.traverse((e=>{e.isMesh&&(e.material.envMap=this.envMap,e.material.needsUpdate=!0)}))),this},updateMatrixWorld:function(t){e.Object3D.prototype.updateMatrixWorld.call(this,t),this.motionController&&(this.motionController.updateFromGamepad(),Object.values(this.motionController.components).forEach((t=>{Object.values(t.visualResponses).forEach((t=>{const{valueNode:n,minNode:r,maxNode:s,value:a,valueNodeProperty:i}=t;n&&(i===o.Constants.VisualResponseProperty.VISIBILITY?n.visible=a:i===o.Constants.VisualResponseProperty.TRANSFORM&&(e.Quaternion.slerp(r.quaternion,s.quaternion,n.quaternion,a),n.position.lerpVectors(r.position,s.position,a)))}))})))}});var s=function(){function e(e=null){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)}return e.prototype={constructor:e,createControllerModel:function(e){const t=new n;let s=null;return e.addEventListener("connected",(e=>{const n=e.data;"tracked-pointer"===n.targetRayMode&&n.gamepad&&o.fetchProfile(n,this.path,"generic-trigger").then((({profile:e,assetPath:a})=>{t.motionController=new o.MotionController(n,e,a);const i=this._assetCache[t.motionController.assetUrl];if(i)s=i.scene.clone(),r(t,s);else{if(!this.gltfLoader)throw new Error("GLTFLoader not set.");this.gltfLoader.setPath(""),this.gltfLoader.load(t.motionController.assetUrl,(e=>{this._assetCache[t.motionController.assetUrl]=e,s=e.scene.clone(),r(t,s)}),null,(()=>{throw new Error(`Asset ${t.motionController.assetUrl} missing or malformed.`)}))}})).catch((e=>{console.warn(e)}))})),e.addEventListener("disconnected",(()=>{t.motionController=null,t.remove(s),s=null})),t}},e}();exports.XRControllerModelFactory=s;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("three"),o=require("../loaders/GLTFLoader.cjs.js"),t=require("../libs/MotionControllers.cjs.js");class n extends e.Object3D{constructor(){super(),this.motionController=null,this.envMap=null}setEnvironmentMap(e){return this.envMap==e||(this.envMap=e,this.traverse((e=>{e.isMesh&&(e.material.envMap=this.envMap,e.material.needsUpdate=!0)}))),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:n,maxNode:r,value:s,valueNodeProperty:a}=e;o&&(a===t.MotionControllerConstants.VisualResponseProperty.VISIBILITY?o.visible=s:a===t.MotionControllerConstants.VisualResponseProperty.TRANSFORM&&(o.quaternion.slerpQuaternions(n.quaternion,r.quaternion,s),o.position.lerpVectors(n.position,r.position,s)))}))})))}}function r(o,n){!function(o,n){Object.values(o.components).forEach((o=>{const{type:r,touchPointNodeName:s,visualResponses:a}=o;if(r===t.MotionControllerConstants.ComponentType.TOUCHPAD)if(o.touchPointNode=n.getObjectByName(s),o.touchPointNode){const t=new e.SphereGeometry(.001),n=new e.MeshBasicMaterial({color:255}),r=new e.Mesh(t,n);o.touchPointNode.add(r)}else console.warn(`Could not find touch dot, ${o.touchPointNodeName}, in touchpad component ${o.id}`);Object.values(a).forEach((e=>{const{valueNodeName:o,minNodeName:r,maxNodeName:s,valueNodeProperty:a}=e;if(a===t.MotionControllerConstants.VisualResponseProperty.TRANSFORM){if(e.minNode=n.getObjectByName(r),e.maxNode=n.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=n.getObjectByName(o),e.valueNode||console.warn(`Could not find ${o} in the model`)}))}))}(o.motionController,n),o.envMap&&n.traverse((e=>{e.isMesh&&(e.material.envMap=o.envMap,e.material.needsUpdate=!0)})),o.add(n)}exports.XRControllerModelFactory=class{constructor(e=null){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 o.GLTFLoader)}createControllerModel(e){const o=new n;let s=null;return e.addEventListener("connected",(e=>{const n=e.data;"tracked-pointer"===n.targetRayMode&&n.gamepad&&t.fetchProfile(n,this.path,"generic-trigger").then((({profile:e,assetPath:a})=>{o.motionController=new t.MotionController(n,e,a);const l=this._assetCache[o.motionController.assetUrl];if(l)s=l.scene.clone(),r(o,s);else{if(!this.gltfLoader)throw new Error("GLTFLoader not set.");this.gltfLoader.setPath(""),this.gltfLoader.load(o.motionController.assetUrl,(e=>{this._assetCache[o.motionController.assetUrl]=e,s=e.scene.clone(),r(o,s)}),null,(()=>{throw new Error(`Asset ${o.motionController.assetUrl} missing or malformed.`)}))}})).catch((e=>{console.warn(e)}))})),e.addEventListener("disconnected",(()=>{o.motionController=null,o.remove(s),s=null})),o}};
@@ -1,19 +1,18 @@
1
- import { Object3D, Quaternion, SphereGeometry, MeshBasicMaterial, Mesh } from 'three';
1
+ import { Object3D, SphereGeometry, MeshBasicMaterial, Mesh } from 'three';
2
2
  import { GLTFLoader } from '../loaders/GLTFLoader.js';
3
- import { Constants, fetchProfile, MotionController } from '@webxr-input-profiles/motion-controllers';
3
+ import { fetchProfile, MotionController, MotionControllerConstants } from '../libs/MotionControllers.js';
4
4
 
5
5
  const DEFAULT_PROFILES_PATH = 'https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles';
6
6
  const DEFAULT_PROFILE = 'generic-trigger';
7
7
 
8
- function XRControllerModel() {
9
- Object3D.call(this);
10
- this.motionController = null;
11
- this.envMap = null;
12
- }
8
+ class XRControllerModel extends Object3D {
9
+ constructor() {
10
+ super();
11
+ this.motionController = null;
12
+ this.envMap = null;
13
+ }
13
14
 
14
- XRControllerModel.prototype = Object.assign(Object.create(Object3D.prototype), {
15
- constructor: XRControllerModel,
16
- setEnvironmentMap: function (envMap) {
15
+ setEnvironmentMap(envMap) {
17
16
  if (this.envMap == envMap) {
18
17
  return this;
19
18
  }
@@ -26,14 +25,15 @@ XRControllerModel.prototype = Object.assign(Object.create(Object3D.prototype), {
26
25
  }
27
26
  });
28
27
  return this;
29
- },
30
-
28
+ }
31
29
  /**
32
30
  * Polls data from the XRInputSource and updates the model's components to match
33
31
  * the real world data
34
32
  */
35
- updateMatrixWorld: function (force) {
36
- Object3D.prototype.updateMatrixWorld.call(this, force);
33
+
34
+
35
+ updateMatrixWorld(force) {
36
+ super.updateMatrixWorld(force);
37
37
  if (!this.motionController) return; // Cause the MotionController to poll the Gamepad for data
38
38
 
39
39
  this.motionController.updateFromGamepad(); // Update the 3D model to reflect the button, thumbstick, and touchpad state
@@ -52,22 +52,24 @@ XRControllerModel.prototype = Object.assign(Object.create(Object3D.prototype), {
52
52
 
53
53
  if (!valueNode) return; // Calculate the new properties based on the weight supplied
54
54
 
55
- if (valueNodeProperty === Constants.VisualResponseProperty.VISIBILITY) {
55
+ if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.VISIBILITY) {
56
56
  valueNode.visible = value;
57
- } else if (valueNodeProperty === Constants.VisualResponseProperty.TRANSFORM) {
58
- Quaternion.slerp(minNode.quaternion, maxNode.quaternion, valueNode.quaternion, value);
57
+ } else if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM) {
58
+ valueNode.quaternion.slerpQuaternions(minNode.quaternion, maxNode.quaternion, value);
59
59
  valueNode.position.lerpVectors(minNode.position, maxNode.position, value);
60
60
  }
61
61
  });
62
62
  });
63
63
  }
64
- });
64
+
65
+ }
65
66
  /**
66
67
  * Walks the model's tree to find the nodes needed to animate the components and
67
68
  * saves them to the motionContoller components for use in the frame loop. When
68
69
  * touchpads are found, attaches a touch dot to them.
69
70
  */
70
71
 
72
+
71
73
  function findNodes(motionController, scene) {
72
74
  // Loop through the components and find the nodes needed for each components' visual responses
73
75
  Object.values(motionController.components).forEach(component => {
@@ -77,7 +79,7 @@ function findNodes(motionController, scene) {
77
79
  visualResponses
78
80
  } = component;
79
81
 
80
- if (type === Constants.ComponentType.TOUCHPAD) {
82
+ if (type === MotionControllerConstants.ComponentType.TOUCHPAD) {
81
83
  component.touchPointNode = scene.getObjectByName(touchPointNodeName);
82
84
 
83
85
  if (component.touchPointNode) {
@@ -102,7 +104,7 @@ function findNodes(motionController, scene) {
102
104
  valueNodeProperty
103
105
  } = visualResponse; // If animating a transform, find the two nodes to be interpolated between.
104
106
 
105
- if (valueNodeProperty === Constants.VisualResponseProperty.TRANSFORM) {
107
+ if (valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM) {
106
108
  visualResponse.minNode = scene.getObjectByName(minNodeName);
107
109
  visualResponse.maxNode = scene.getObjectByName(maxNodeName); // If the extents cannot be found, skip this animation
108
110
 
@@ -144,8 +146,8 @@ function addAssetSceneToControllerModel(controllerModel, scene) {
144
146
  controllerModel.add(scene);
145
147
  }
146
148
 
147
- var XRControllerModelFactory = function () {
148
- function XRControllerModelFactory(gltfLoader = null) {
149
+ class XRControllerModelFactory {
150
+ constructor(gltfLoader = null) {
149
151
  this.gltfLoader = gltfLoader;
150
152
  this.path = DEFAULT_PROFILES_PATH;
151
153
  this._assetCache = {}; // If a GLTFLoader wasn't supplied to the constructor create a new one.
@@ -155,51 +157,48 @@ var XRControllerModelFactory = function () {
155
157
  }
156
158
  }
157
159
 
158
- XRControllerModelFactory.prototype = {
159
- constructor: XRControllerModelFactory,
160
- createControllerModel: function (controller) {
161
- const controllerModel = new XRControllerModel();
162
- let scene = null;
163
- controller.addEventListener('connected', event => {
164
- const xrInputSource = event.data;
165
- if (xrInputSource.targetRayMode !== 'tracked-pointer' || !xrInputSource.gamepad) return;
166
- fetchProfile(xrInputSource, this.path, DEFAULT_PROFILE).then(({
167
- profile,
168
- assetPath
169
- }) => {
170
- controllerModel.motionController = new MotionController(xrInputSource, profile, assetPath);
171
- const cachedAsset = this._assetCache[controllerModel.motionController.assetUrl];
172
-
173
- if (cachedAsset) {
174
- scene = cachedAsset.scene.clone();
175
- addAssetSceneToControllerModel(controllerModel, scene);
176
- } else {
177
- if (!this.gltfLoader) {
178
- throw new Error('GLTFLoader not set.');
179
- }
180
-
181
- this.gltfLoader.setPath('');
182
- this.gltfLoader.load(controllerModel.motionController.assetUrl, asset => {
183
- this._assetCache[controllerModel.motionController.assetUrl] = asset;
184
- scene = asset.scene.clone();
185
- addAssetSceneToControllerModel(controllerModel, scene);
186
- }, null, () => {
187
- throw new Error(`Asset ${controllerModel.motionController.assetUrl} missing or malformed.`);
188
- });
160
+ createControllerModel(controller) {
161
+ const controllerModel = new XRControllerModel();
162
+ let scene = null;
163
+ controller.addEventListener('connected', event => {
164
+ const xrInputSource = event.data;
165
+ if (xrInputSource.targetRayMode !== 'tracked-pointer' || !xrInputSource.gamepad) return;
166
+ fetchProfile(xrInputSource, this.path, DEFAULT_PROFILE).then(({
167
+ profile,
168
+ assetPath
169
+ }) => {
170
+ controllerModel.motionController = new MotionController(xrInputSource, profile, assetPath);
171
+ const cachedAsset = this._assetCache[controllerModel.motionController.assetUrl];
172
+
173
+ if (cachedAsset) {
174
+ scene = cachedAsset.scene.clone();
175
+ addAssetSceneToControllerModel(controllerModel, scene);
176
+ } else {
177
+ if (!this.gltfLoader) {
178
+ throw new Error('GLTFLoader not set.');
189
179
  }
190
- }).catch(err => {
191
- console.warn(err);
192
- });
193
- });
194
- controller.addEventListener('disconnected', () => {
195
- controllerModel.motionController = null;
196
- controllerModel.remove(scene);
197
- scene = null;
180
+
181
+ this.gltfLoader.setPath('');
182
+ this.gltfLoader.load(controllerModel.motionController.assetUrl, asset => {
183
+ this._assetCache[controllerModel.motionController.assetUrl] = asset;
184
+ scene = asset.scene.clone();
185
+ addAssetSceneToControllerModel(controllerModel, scene);
186
+ }, null, () => {
187
+ throw new Error(`Asset ${controllerModel.motionController.assetUrl} missing or malformed.`);
188
+ });
189
+ }
190
+ }).catch(err => {
191
+ console.warn(err);
198
192
  });
199
- return controllerModel;
200
- }
201
- };
202
- return XRControllerModelFactory;
203
- }();
193
+ });
194
+ controller.addEventListener('disconnected', () => {
195
+ controllerModel.motionController = null;
196
+ controllerModel.remove(scene);
197
+ scene = null;
198
+ });
199
+ return controllerModel;
200
+ }
201
+
202
+ }
204
203
 
205
204
  export { XRControllerModelFactory };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("three");class i{constructor(i,e,n,s,r){this.xrLight=i,this.renderer=e,this.lightProbe=n,this.xrWebGLBinding=null,this.estimationStartCallback=r,this.frameCallback=this.onXRFrame.bind(this);const h=e.xr.getSession();if(s&&"XRWebGLBinding"in window){const n=new t.WebGLCubeRenderTarget(16);i.environment=n.texture;const s=e.getContext();switch(h.preferredReflectionFormat){case"srgba8":s.getExtension("EXT_sRGB");break;case"rgba16f":s.getExtension("OES_texture_half_float")}this.xrWebGLBinding=new XRWebGLBinding(h,s),this.lightProbe.addEventListener("reflectionchange",(()=>{this.updateReflection()}))}h.requestAnimationFrame(this.frameCallback)}updateReflection(){const t=this.renderer.properties.get(this.xrLight.environment);if(t){const i=this.xrWebGLBinding.getReflectionCubeMap(this.lightProbe);i&&(t.__webglTexture=i)}}onXRFrame(t,i){if(!this.xrLight)return;i.session.requestAnimationFrame(this.frameCallback);const e=i.getLightEstimate(this.lightProbe);if(e){this.xrLight.lightProbe.sh.fromArray(e.sphericalHarmonicsCoefficients),this.xrLight.lightProbe.intensity=1;const t=Math.max(1,Math.max(e.primaryLightIntensity.x,Math.max(e.primaryLightIntensity.y,e.primaryLightIntensity.z)));this.xrLight.directionalLight.color.setRGB(e.primaryLightIntensity.x/t,e.primaryLightIntensity.y/t,e.primaryLightIntensity.z/t),this.xrLight.directionalLight.intensity=t,this.xrLight.directionalLight.position.copy(e.primaryLightDirection),this.estimationStartCallback&&(this.estimationStartCallback(),this.estimationStartCallback=null)}}dispose(){this.xrLight=null,this.renderer=null,this.lightProbe=null,this.xrWebGLBinding=null}}class e extends t.Group{constructor(e,n=!0){super(),this.lightProbe=new t.LightProbe,this.lightProbe.intensity=0,this.add(this.lightProbe),this.directionalLight=new t.DirectionalLight,this.directionalLight.intensity=0,this.add(this.directionalLight),this.environment=null;let s=null,r=!1;e.xr.addEventListener("sessionstart",(()=>{const t=e.xr.getSession();"requestLightProbe"in t&&t.requestLightProbe({reflectionFormat:t.preferredReflectionFormat}).then((t=>{s=new i(this,e,t,n,(()=>{r=!0,this.dispatchEvent({type:"estimationstart"})}))}))})),e.xr.addEventListener("sessionend",(()=>{s&&(s.dispose(),s=null),r&&this.dispatchEvent({type:"estimationend"})})),this.dispose=()=>{s&&(s.dispose(),s=null),this.remove(this.lightProbe),this.lightProbe=null,this.remove(this.directionalLight),this.directionalLight=null,this.environment=null}}}exports.XREstimatedLight=e;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("three");class i{constructor(i,e,n,s,r){this.xrLight=i,this.renderer=e,this.lightProbe=n,this.xrWebGLBinding=null,this.estimationStartCallback=r,this.frameCallback=this.onXRFrame.bind(this);const h=e.xr.getSession();if(s&&"XRWebGLBinding"in window){const n=new t.WebGLCubeRenderTarget(16);i.environment=n.texture;const s=e.getContext();switch(h.preferredReflectionFormat){case"srgba8":s.getExtension("EXT_sRGB");break;case"rgba16f":s.getExtension("OES_texture_half_float")}this.xrWebGLBinding=new XRWebGLBinding(h,s),this.lightProbe.addEventListener("reflectionchange",(()=>{this.updateReflection()}))}h.requestAnimationFrame(this.frameCallback)}updateReflection(){const t=this.renderer.properties.get(this.xrLight.environment);if(t){const i=this.xrWebGLBinding.getReflectionCubeMap(this.lightProbe);i&&(t.__webglTexture=i,this.xrLight.environment.needsPMREMUpdate=!0)}}onXRFrame(t,i){if(!this.xrLight)return;i.session.requestAnimationFrame(this.frameCallback);const e=i.getLightEstimate(this.lightProbe);if(e){this.xrLight.lightProbe.sh.fromArray(e.sphericalHarmonicsCoefficients),this.xrLight.lightProbe.intensity=1;const t=Math.max(1,Math.max(e.primaryLightIntensity.x,Math.max(e.primaryLightIntensity.y,e.primaryLightIntensity.z)));this.xrLight.directionalLight.color.setRGB(e.primaryLightIntensity.x/t,e.primaryLightIntensity.y/t,e.primaryLightIntensity.z/t),this.xrLight.directionalLight.intensity=t,this.xrLight.directionalLight.position.copy(e.primaryLightDirection),this.estimationStartCallback&&(this.estimationStartCallback(),this.estimationStartCallback=null)}}dispose(){this.xrLight=null,this.renderer=null,this.lightProbe=null,this.xrWebGLBinding=null}}class e extends t.Group{constructor(e,n=!0){super(),this.lightProbe=new t.LightProbe,this.lightProbe.intensity=0,this.add(this.lightProbe),this.directionalLight=new t.DirectionalLight,this.directionalLight.intensity=0,this.add(this.directionalLight),this.environment=null;let s=null,r=!1;e.xr.addEventListener("sessionstart",(()=>{const t=e.xr.getSession();"requestLightProbe"in t&&t.requestLightProbe({reflectionFormat:t.preferredReflectionFormat}).then((t=>{s=new i(this,e,t,n,(()=>{r=!0,this.dispatchEvent({type:"estimationstart"})}))}))})),e.xr.addEventListener("sessionend",(()=>{s&&(s.dispose(),s=null),r&&this.dispatchEvent({type:"estimationend"})})),this.dispose=()=>{s&&(s.dispose(),s=null),this.remove(this.lightProbe),this.lightProbe=null,this.remove(this.directionalLight),this.directionalLight=null,this.environment=null}}}exports.XREstimatedLight=e;
@@ -46,6 +46,7 @@ class SessionLightProbe {
46
46
 
47
47
  if (cubeMap) {
48
48
  textureProperties.__webglTexture = cubeMap;
49
+ this.xrLight.environment.needsPMREMUpdate = true;
49
50
  }
50
51
  }
51
52
  }
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../loaders/GLTFLoader.cjs.js");require("three");exports.XRHandMeshModel=class{constructor(i,n,a,t){this.controller=n,this.handModel=i,this.bones=[];const r=new e.GLTFLoader;r.setPath(a||"https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles/generic-hand/"),r.load(`${t}.glb`,(e=>{const i=e.scene.children[0];this.handModel.add(i);const n=i.getObjectByProperty("type","SkinnedMesh");n.frustumCulled=!1,n.castShadow=!0,n.receiveShadow=!0;["wrist","thumb-metacarpal","thumb-phalanx-proximal","thumb-phalanx-distal","thumb-tip","index-finger-metacarpal","index-finger-phalanx-proximal","index-finger-phalanx-intermediate","index-finger-phalanx-distal","index-finger-tip","middle-finger-metacarpal","middle-finger-phalanx-proximal","middle-finger-phalanx-intermediate","middle-finger-phalanx-distal","middle-finger-tip","ring-finger-metacarpal","ring-finger-phalanx-proximal","ring-finger-phalanx-intermediate","ring-finger-phalanx-distal","ring-finger-tip","pinky-finger-metacarpal","pinky-finger-phalanx-proximal","pinky-finger-phalanx-intermediate","pinky-finger-phalanx-distal","pinky-finger-tip"].forEach((e=>{const n=i.getObjectByName(e);void 0!==n?n.jointName=e:console.warn(`Couldn't find ${e} in ${t} hand mesh`),this.bones.push(n)}))}))}updateMesh(){const e=this.controller.joints;for(let i=0;i<this.bones.length;i++){const n=this.bones[i];if(n){const i=e[n.jointName];if(i.visible){const e=i.position;n.position.copy(e),n.quaternion.copy(i.quaternion)}}}}};
@@ -0,0 +1,11 @@
1
+ import { Object3D } from 'three';
2
+
3
+ export class XRHandMeshModel {
4
+ controller: Object3D;
5
+ handModel: Object3D;
6
+ bones: Object3D[];
7
+
8
+ constructor(handModel: Object3D, controller: Object3D, path: string, handedness: string);
9
+
10
+ updateMesh(): void;
11
+ }