three-stdlib 2.8.4 → 2.8.5

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.
@@ -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
+ }