|
8 | 8 | this.rightViewMatrix = mat4.create();
|
9 | 9 | this.sitStandMatrix = mat4.create();
|
10 | 10 | this.gamepads = [];
|
| 11 | + this.controllerA = new XRControllerData(); |
| 12 | + this.controllerB = new XRControllerData(); |
11 | 13 | this.xrData = null;
|
12 | 14 | }
|
| 15 | + |
| 16 | + function XRControllerData() { |
| 17 | + // TODO: set enabled 0 if controller was enable and then disable |
| 18 | + this.enabled = 0; |
| 19 | + this.hand = 0; |
| 20 | + this.positionX = 0; |
| 21 | + this.positionY = 0; |
| 22 | + this.positionZ = 0; |
| 23 | + this.rotationX = 0; |
| 24 | + this.rotationY = 0; |
| 25 | + this.rotationZ = 0; |
| 26 | + this.rotationW = 0; |
| 27 | + this.trigger = 0; |
| 28 | + this.squeeze = 0; |
| 29 | + this.thumbstick = 0; |
| 30 | + this.thumbstickX = 0; |
| 31 | + this.thumbstickY = 0; |
| 32 | + this.touchpad = 0; |
| 33 | + this.touchpadX = 0; |
| 34 | + this.touchpadY = 0; |
| 35 | + this.buttonA = 0; |
| 36 | + this.buttonB = 0; |
| 37 | + } |
13 | 38 |
|
14 | 39 | function XRManager() {
|
15 | 40 | this.arSession = null;
|
|
24 | 49 | this.isARSupported = false;
|
25 | 50 | this.isVRSupported = false;
|
26 | 51 | this.rAFCB = null;
|
| 52 | + this.onInputEvent = null; |
27 | 53 | this.init();
|
28 | 54 | }
|
29 | 55 |
|
|
112 | 138 | XRManager.prototype.onEndSession = function (xrSessionEvent) {
|
113 | 139 | if (xrSessionEvent.session) {
|
114 | 140 | xrSessionEvent.session.isInSession = false;
|
| 141 | + xrSessionEvent.session.removeEventListener('select', this.onInputEvent); |
| 142 | + xrSessionEvent.session.removeEventListener('selectstart', this.onInputEvent); |
| 143 | + xrSessionEvent.session.removeEventListener('selectend', this.onInputEvent); |
| 144 | + xrSessionEvent.session.removeEventListener('squeeze', this.onInputEvent); |
| 145 | + xrSessionEvent.session.removeEventListener('squeezestart', this.onInputEvent); |
| 146 | + xrSessionEvent.session.removeEventListener('squeezeend', this.onInputEvent); |
115 | 147 | }
|
116 | 148 |
|
117 | 149 | this.gameInstance.Module.WebXR.OnEndXR();
|
118 | 150 | this.didNotifyUnity = false;
|
119 | 151 | this.canvas.width = this.canvas.parentElement.clientWidth * window.devicePixelRatio;
|
120 | 152 | this.canvas.height = this.canvas.parentElement.clientHeight * window.devicePixelRatio;
|
121 | 153 | }
|
| 154 | + |
| 155 | + XRManager.prototype.onInputSourceEvent = function (xrInputSourceEvent) { |
| 156 | + if (xrInputSourceEvent.type && xrInputSourceEvent.inputSource |
| 157 | + && xrInputSourceEvent.inputSource.handedness) { |
| 158 | + var hand = 0; |
| 159 | + var inputSource = xrInputSourceEvent.inputSource; |
| 160 | + var xrData = this.xrData; |
| 161 | + var controller = this.xrData.controllerA; |
| 162 | + if (inputSource.handedness == 'left') { |
| 163 | + hand = 1; |
| 164 | + controller = this.xrData.controllerB; |
| 165 | + } else if (inputSource.handedness == 'right') { |
| 166 | + hand = 2; |
| 167 | + } |
| 168 | + |
| 169 | + controller.enabled = 1; |
| 170 | + controller.hand = hand; |
| 171 | + |
| 172 | + switch (xrInputSourceEvent.type) { |
| 173 | + case "select": |
| 174 | + controller.trigger = 1; |
| 175 | + break; |
| 176 | + case "selectstart": |
| 177 | + controller.trigger = 1; |
| 178 | + break; |
| 179 | + case "selectend": |
| 180 | + controller.trigger = 0; |
| 181 | + break; |
| 182 | + case "squeeze": |
| 183 | + controller.squeeze = 1; |
| 184 | + break; |
| 185 | + case "squeezestart": |
| 186 | + controller.squeeze = 1; |
| 187 | + break; |
| 188 | + case "squeezeend": |
| 189 | + controller.squeeze = 0; |
| 190 | + break; |
| 191 | + } |
| 192 | + |
| 193 | + if (hand == 0 || hand == 2) { |
| 194 | + xrData.controllerA = controller; |
| 195 | + } else { |
| 196 | + xrData.controllerB = controller; |
| 197 | + } |
| 198 | + } |
| 199 | + } |
122 | 200 |
|
123 | 201 | XRManager.prototype.toggleAr = function () {
|
124 | 202 | if (!this.gameInstance)
|
|
209 | 287 | document.dispatchEvent(new CustomEvent('onVRSupportedCheck', { detail:{supported:this.isVRSupported} }));
|
210 | 288 |
|
211 | 289 | this.UpdateXRCapabilities();
|
| 290 | + |
| 291 | + this.onInputEvent = this.onInputSourceEvent.bind(this); |
212 | 292 |
|
213 | 293 | navigator.xr.isSessionSupported('inline').then((supported) => {
|
214 | 294 | if (supported) {
|
|
232 | 312 | })
|
233 | 313 | );
|
234 | 314 | }
|
235 |
| - |
236 |
| - XRManager.prototype.getGamepadAxes = function(gamepad) { |
237 |
| - var axes = []; |
238 |
| - for (var i = 0; i < gamepad.axes.length; i++) { |
239 |
| - axes.push(gamepad.axes[i]); |
240 |
| - } |
241 |
| - return axes; |
242 |
| - } |
243 |
| - |
244 |
| - XRManager.prototype.getGamepadButtons = function(gamepad) { |
245 |
| - var buttons = []; |
246 |
| - for (var i = 0; i < gamepad.buttons.length; i++) { |
247 |
| - buttons.push({ |
248 |
| - pressed: gamepad.buttons[i].pressed, |
249 |
| - touched: gamepad.buttons[i].touched, |
250 |
| - value: gamepad.buttons[i].value |
251 |
| - }); |
252 |
| - } |
253 |
| - return buttons; |
254 |
| - } |
255 |
| - |
256 |
| - XRManager.prototype.getXRGamepads = function(frame, inputSources, refSpace) { |
257 |
| - var vrGamepads = [] |
| 315 | + |
| 316 | + XRManager.prototype.getXRControllersData = function(frame, inputSources, refSpace, xrData) { |
258 | 317 | if (!inputSources || !inputSources.length) {
|
259 |
| - return vrGamepads; |
| 318 | + return; |
260 | 319 | }
|
261 | 320 | for (var i = 0; i < inputSources.length; i++) {
|
262 | 321 | let inputSource = inputSources[i];
|
263 | 322 | // Show the input source if it has a grip space
|
264 |
| - if (inputSource.gripSpace && inputSource.gamepad) { |
| 323 | + if (inputSource.gripSpace) { |
265 | 324 | let inputPose = frame.getPose(inputSource.gripSpace, refSpace);
|
266 | 325 |
|
267 | 326 | var position = inputPose.transform.position;
|
268 | 327 | var orientation = inputPose.transform.orientation;
|
269 |
| - |
270 |
| - vrGamepads.push({ |
271 |
| - id: inputSource.gamepad.id, |
272 |
| - index: inputSource.gamepad.index, |
273 |
| - hand: inputSource.handedness, |
274 |
| - buttons: this.getGamepadButtons(inputSource.gamepad), |
275 |
| - axes: this.getGamepadAxes(inputSource.gamepad), |
276 |
| - hasOrientation: true, |
277 |
| - hasPosition: true, |
278 |
| - orientation: this.GLQuaternionToUnity([orientation.x, orientation.y, orientation.z, orientation.w]), |
279 |
| - position: this.GLVec3ToUnity([position.x, position.y, position.z]), |
280 |
| - linearAcceleration: [0, 0, 0], |
281 |
| - linearVelocity: [0, 0, 0] |
282 |
| - }); |
| 328 | + var hand = 0; |
| 329 | + var controller = xrData.controllerA; |
| 330 | + if (inputSource.handedness == 'left') { |
| 331 | + hand = 1; |
| 332 | + controller = xrData.controllerB; |
| 333 | + } else if (inputSource.handedness == 'right') { |
| 334 | + hand = 2; |
| 335 | + } |
| 336 | + |
| 337 | + controller.enabled = 1; |
| 338 | + controller.hand = hand; |
| 339 | + |
| 340 | + controller.positionX = position.x; |
| 341 | + controller.positionY = position.y; |
| 342 | + controller.positionZ = -position.z; |
| 343 | + |
| 344 | + controller.rotationX = -orientation.x; |
| 345 | + controller.rotationY = -orientation.y; |
| 346 | + controller.rotationZ = orientation.z; |
| 347 | + controller.rotationW = orientation.w; |
| 348 | + |
| 349 | + // if there's gamepad, use the xr-standard mapping |
| 350 | + // TODO: check for profiles |
| 351 | + if (inputSource.gamepad) { |
| 352 | + for (var j = 0; j < inputSource.gamepad.buttons.length; j++) { |
| 353 | + switch (j) { |
| 354 | + case 0: |
| 355 | + controller.trigger = inputSource.gamepad.buttons[j].value; |
| 356 | + break; |
| 357 | + case 1: |
| 358 | + controller.squeeze = inputSource.gamepad.buttons[j].value; |
| 359 | + break; |
| 360 | + case 2: |
| 361 | + controller.touchpad = inputSource.gamepad.buttons[j].value; |
| 362 | + break; |
| 363 | + case 3: |
| 364 | + controller.thumbstick = inputSource.gamepad.buttons[j].value; |
| 365 | + break; |
| 366 | + case 4: |
| 367 | + controller.buttonA = inputSource.gamepad.buttons[j].value; |
| 368 | + break; |
| 369 | + case 5: |
| 370 | + controller.buttonB = inputSource.gamepad.buttons[j].value; |
| 371 | + break; |
| 372 | + } |
| 373 | + } |
| 374 | + for (var j = 0; j < inputSource.gamepad.axes.length; j++) { |
| 375 | + switch (j) { |
| 376 | + case 0: |
| 377 | + controller.touchpadX = inputSource.gamepad.axes[j].value; |
| 378 | + break; |
| 379 | + case 1: |
| 380 | + controller.touchpadY = inputSource.gamepad.axes[j].value; |
| 381 | + break; |
| 382 | + case 2: |
| 383 | + controller.thumbstickX = inputSource.gamepad.axes[j].value; |
| 384 | + break; |
| 385 | + case 3: |
| 386 | + controller.thumbstickY = inputSource.gamepad.axes[j].value; |
| 387 | + break; |
| 388 | + } |
| 389 | + } |
| 390 | + } |
| 391 | + |
| 392 | + if (hand == 0 || hand == 2) { |
| 393 | + xrData.controllerA = controller; |
| 394 | + } else { |
| 395 | + xrData.controllerB = controller; |
| 396 | + } |
283 | 397 | }
|
284 | 398 | }
|
285 |
| - return vrGamepads; |
286 | 399 | }
|
287 | 400 |
|
288 | 401 | // Convert WebGL to Unity compatible Vector3
|
|
322 | 435 | let glLayer = new XRWebGLLayer(session, this.ctx);
|
323 | 436 | session.updateRenderState({ baseLayer: glLayer });
|
324 | 437 |
|
| 438 | + |
| 439 | + |
325 | 440 | let refSpaceType = 'viewer';
|
326 | 441 | if (session.isImmersive) {
|
327 | 442 | refSpaceType = 'local-floor';
|
|
331 | 446 |
|
332 | 447 | this.canvas.width = glLayer.framebufferWidth;
|
333 | 448 | this.canvas.height = glLayer.framebufferHeight;
|
| 449 | + |
| 450 | + session.addEventListener('select', this.onInputEvent); |
| 451 | + session.addEventListener('selectstart', this.onInputEvent); |
| 452 | + session.addEventListener('selectend', this.onInputEvent); |
| 453 | + session.addEventListener('squeeze', this.onInputEvent); |
| 454 | + session.addEventListener('squeezestart', this.onInputEvent); |
| 455 | + session.addEventListener('squeezeend', this.onInputEvent); |
334 | 456 | }
|
335 | 457 |
|
336 | 458 | session.requestReferenceSpace(refSpaceType).then((refSpace) => {
|
|
387 | 509 | }
|
388 | 510 | }
|
389 | 511 |
|
390 |
| - // Gamepads |
391 |
| - xrData.gamepads = this.getXRGamepads(frame, session.inputSources, session.refSpace); |
392 |
| - |
| 512 | + this.getXRControllersData(frame, session.inputSources, session.refSpace, xrData); |
| 513 | + |
393 | 514 | // Dispatch event with headset data to be handled in webxr.jslib
|
394 | 515 | document.dispatchEvent(new CustomEvent('XRData', { detail: {
|
395 | 516 | leftProjectionMatrix: xrData.leftProjectionMatrix,
|
396 | 517 | rightProjectionMatrix: xrData.rightProjectionMatrix,
|
397 | 518 | leftViewMatrix: xrData.leftViewMatrix,
|
398 | 519 | rightViewMatrix: xrData.rightViewMatrix,
|
399 |
| - sitStandMatrix: xrData.sitStandMatrix |
| 520 | + sitStandMatrix: xrData.sitStandMatrix, |
| 521 | + controllerA: xrData.controllerA, |
| 522 | + controllerB: xrData.controllerB |
400 | 523 | }}));
|
401 | 524 |
|
402 | 525 | if (!this.didNotifyUnity)
|
|
409 | 532 | }
|
410 | 533 | this.didNotifyUnity = true;
|
411 | 534 | }
|
412 |
| - |
413 |
| - this.gameInstance.Module.WebXR.OnWebXRData( |
414 |
| - JSON.stringify({ |
415 |
| - controllers: xrData.gamepads |
416 |
| - })); |
417 |
| - } |
418 |
| - |
419 |
| - // Show instruction dialogue for non-VR enabled browsers. |
420 |
| - XRManager.prototype.displayElement = function (el) { |
421 |
| - if (el.dataset.enabled) { |
422 |
| - return; |
423 |
| - } |
424 |
| - var confirmButton = el.querySelector('button'); |
425 |
| - el.dataset.enabled = true; |
426 |
| - |
427 |
| - function onConfirm () { |
428 |
| - el.dataset.enabled = false; |
429 |
| - confirmButton.removeEventListener('click', onConfirm); |
430 |
| - } |
431 |
| - confirmButton.addEventListener('click', onConfirm); |
432 | 535 | }
|
433 | 536 |
|
434 | 537 | function initWebXRManager () {
|
|
0 commit comments