From a161565c8d954e122935986307859fc6b422725d Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Sun, 7 Apr 2024 20:45:08 +0200 Subject: [PATCH 01/11] Removed unnecessary session check, done in btn --- src/p5xr/p5ar/p5ar.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/p5xr/p5ar/p5ar.js b/src/p5xr/p5ar/p5ar.js index 389eefa..deff65f 100644 --- a/src/p5xr/p5ar/p5ar.js +++ b/src/p5xr/p5ar/p5ar.js @@ -9,10 +9,6 @@ export default class p5ar extends p5xr { initAR() { this.__createButton(); - // WebXR available - if (navigator?.xr) { - this.__sessionCheck(); - } } //* ********************************************************// From 12bb5425ef5d07bd1876c22070b840ab00e51271 Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Sun, 7 Apr 2024 20:46:42 +0200 Subject: [PATCH 02/11] Removed deprecated navigator.getUserMedia() https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia --- src/p5xr/p5ar/p5ar.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/p5xr/p5ar/p5ar.js b/src/p5xr/p5ar/p5ar.js index deff65f..7e3021e 100644 --- a/src/p5xr/p5ar/p5ar.js +++ b/src/p5xr/p5ar/p5ar.js @@ -102,13 +102,6 @@ export default class p5ar extends p5xr { * @ignore */ __onXRButtonClicked() { - // Normalize the various vendor prefixed versions of getUserMedia. - navigator.getUserMedia = - navigator.getUserMedia || - navigator.webkitGetUserMedia || - navigator.mozGetUserMedia || - navigator.msGetUserMedia; - navigator.xr .requestSession('immersive-ar', { requiredFeatures: ['local', 'hit-test'], From 201c2cb7669c16b635bfb26912e412966231f7ce Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Sun, 7 Apr 2024 21:55:30 +0200 Subject: [PATCH 03/11] Removed superfluous init functions, create buttons in constructors Removed button argument because it was always created and overloaded afer construction --- src/app.js | 6 ++---- src/p5xr/core/p5xr.js | 3 +-- src/p5xr/p5ar/p5ar.js | 3 --- src/p5xr/p5vr/p5vr.js | 9 --------- 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/app.js b/src/app.js index fe3b59d..bbe924f 100644 --- a/src/app.js +++ b/src/app.js @@ -26,10 +26,9 @@ window.p5xr = { * @section VR * @category Initialization */ -p5.prototype.createVRCanvas = function (xrButton) { +p5.prototype.createVRCanvas = function () { noLoop(); - p5xr.instance = new p5vr(xrButton); - p5xr.instance.__initVR(); + p5xr.instance = new p5vr(); }; /** @@ -46,7 +45,6 @@ p5.prototype.createVRCanvas = function (xrButton) { p5.prototype.createARCanvas = function () { noLoop(); p5xr.instance = new p5ar(); - p5xr.instance.initAR(); }; /** diff --git a/src/p5xr/core/p5xr.js b/src/p5xr/core/p5xr.js index d6cce77..30e276d 100644 --- a/src/p5xr/core/p5xr.js +++ b/src/p5xr/core/p5xr.js @@ -16,9 +16,8 @@ import p5xrInput from './p5xrInput'; * @property curClearColor {Color} background clear color set by global `setVRBackgroundColor` */ export default class p5xr { - constructor(xrButton) { + constructor() { this.xrDevice = null; - this.xrButton = xrButton || null; this.isVR = null; this.hasImmersive = null; this.xrSession = null; diff --git a/src/p5xr/p5ar/p5ar.js b/src/p5xr/p5ar/p5ar.js index 7e3021e..e256210 100644 --- a/src/p5xr/p5ar/p5ar.js +++ b/src/p5xr/p5ar/p5ar.js @@ -5,9 +5,6 @@ export default class p5ar extends p5xr { constructor() { super(); this.canvas = null; - } - - initAR() { this.__createButton(); } diff --git a/src/p5xr/p5vr/p5vr.js b/src/p5xr/p5vr/p5vr.js index 39bc1cb..6cc9091 100644 --- a/src/p5xr/p5vr/p5vr.js +++ b/src/p5xr/p5vr/p5vr.js @@ -25,15 +25,6 @@ export default class p5vr extends p5xr { if (navigator?.xr) { navigator.xr.requestSession('inline').then(this.__startSketch.bind(this)); } - } - - /** - * Currently a stub function that just creates a button - * Previously handled more, now can be replaced with refactor - * @private - * @ignore - */ - __initVR() { this.__createButton(); } From df52b0117659243e1a66c40f65ac792a6d2f6615 Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Sun, 7 Apr 2024 22:01:35 +0200 Subject: [PATCH 04/11] Moved isImmersive to XR level, AR and VR can both be immersive --- src/p5xr/core/p5xr.js | 1 + src/p5xr/p5vr/p5vr.js | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p5xr/core/p5xr.js b/src/p5xr/core/p5xr.js index 30e276d..660aa7c 100644 --- a/src/p5xr/core/p5xr.js +++ b/src/p5xr/core/p5xr.js @@ -20,6 +20,7 @@ export default class p5xr { this.xrDevice = null; this.isVR = null; this.hasImmersive = null; + this.isImmersive = false; this.xrSession = null; this.xrRefSpace = null; this.xrViewerSpace = null; diff --git a/src/p5xr/p5vr/p5vr.js b/src/p5xr/p5vr/p5vr.js index 6cc9091..f047155 100644 --- a/src/p5xr/p5vr/p5vr.js +++ b/src/p5xr/p5vr/p5vr.js @@ -13,7 +13,6 @@ export default class p5vr extends p5xr { constructor() { super(); this.isVR = true; - this.isImmersive = false; this.lookYaw = 0; this.lookPitch = 0; this.LOOK_SPEED = 0.0025; From 446d7c12462ac6a3b22d425053426a36df24be04 Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Sun, 7 Apr 2024 22:34:02 +0200 Subject: [PATCH 05/11] Favour explicited WebXR modes --- src/p5xr/core/p5xr.js | 10 +++++----- src/p5xr/core/p5xrButton.js | 7 ++++--- src/p5xr/p5ar/p5ar.js | 1 + src/p5xr/p5vr/p5vr.js | 1 + 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/p5xr/core/p5xr.js b/src/p5xr/core/p5xr.js index 660aa7c..182db07 100644 --- a/src/p5xr/core/p5xr.js +++ b/src/p5xr/core/p5xr.js @@ -8,6 +8,7 @@ import p5xrInput from './p5xrInput'; * * @constructor * + * @property mode {"inline" | "immersive-ar" | "immersive-vr"} WebXR session mode * @property vrDevice {XRDevice} the current VR compatible device * @property vrSession {XRSession} the current VR session * @property vrFrameOfRef {XRFrameOfReference} the current VR frame of reference @@ -19,6 +20,7 @@ export default class p5xr { constructor() { this.xrDevice = null; this.isVR = null; + this.mode = 'inline'; this.hasImmersive = null; this.isImmersive = false; this.xrSession = null; @@ -27,7 +29,7 @@ export default class p5xr { this.xrHitTestSource = null; this.frame = null; this.gl = null; - this.curClearColor = color(255, 255, 255); + this.curClearColor = color(256, 255, 255); this.viewer = new p5xrViewer(); } @@ -125,11 +127,9 @@ export default class p5xr { // WebXR availabilty if (navigator?.xr) { console.log('XR Available'); - const mode = this.isVR ? 'VR' : 'AR'; - const session = this.isVR ? 'immersive-vr' : 'immersive-ar'; - const supported = await navigator.xr.isSessionSupported(session); + const supported = await navigator.xr.isSessionSupported(this.mode); this.hasImmersive = supported; - this.xrButton.setAvailable(supported, mode); + this.xrButton.setAvailable(supported, this.mode); } else { console.log('XR Not Available'); this.xrButton.disable(); diff --git a/src/p5xr/core/p5xrButton.js b/src/p5xr/core/p5xrButton.js index 6898ef8..26fd982 100644 --- a/src/p5xr/core/p5xrButton.js +++ b/src/p5xr/core/p5xrButton.js @@ -422,18 +422,19 @@ class p5xrButton { * Set button state based on mode support */ setAvailable(isAvailable, mode) { + const displayMode = mode.slice(-2).toUpperCase(); if (isAvailable) { - const msg = `Enter ${mode}`; + const msg = `Enter ${displayMode}`; this.setTitle(msg); this.setTooltip(msg); this.enable(); console.log(`${mode} supported`); this.setDevice(true); - } else if (mode === 'VR') { + } else if (displayMode === 'VR') { console.log('VR not supported. Falling back to inline mode.'); this.hide(); } else { - const msg = `${mode} not supported`; + const msg = `${displayMode} not supported`; this.setTitle(msg); this.setTooltip(msg); this.disable(); diff --git a/src/p5xr/p5ar/p5ar.js b/src/p5xr/p5ar/p5ar.js index e256210..ee281ce 100644 --- a/src/p5xr/p5ar/p5ar.js +++ b/src/p5xr/p5ar/p5ar.js @@ -4,6 +4,7 @@ import ARAnchor from './ARAnchor'; export default class p5ar extends p5xr { constructor() { super(); + this.mode = 'immersive-ar'; this.canvas = null; this.__createButton(); } diff --git a/src/p5xr/p5vr/p5vr.js b/src/p5xr/p5vr/p5vr.js index f047155..c19f189 100644 --- a/src/p5xr/p5vr/p5vr.js +++ b/src/p5xr/p5vr/p5vr.js @@ -12,6 +12,7 @@ import p5xr from '../core/p5xr'; export default class p5vr extends p5xr { constructor() { super(); + this.mode = 'immersive-vr'; this.isVR = true; this.lookYaw = 0; this.lookPitch = 0; From df07ee28b629da89b29caa1fb6ee999b9261e269 Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Sun, 7 Apr 2024 23:37:40 +0200 Subject: [PATCH 06/11] Moved common requestSession code into p5xr from p5ar and p5vr --- src/p5xr/core/p5xr.js | 58 ++++++++++++++++++++++++++++++++++++++++++- src/p5xr/p5ar/p5ar.js | 25 +++---------------- src/p5xr/p5vr/p5vr.js | 33 ------------------------ 3 files changed, 60 insertions(+), 56 deletions(-) diff --git a/src/p5xr/core/p5xr.js b/src/p5xr/core/p5xr.js index 182db07..0d5d1d6 100644 --- a/src/p5xr/core/p5xr.js +++ b/src/p5xr/core/p5xr.js @@ -8,6 +8,15 @@ import p5xrInput from './p5xrInput'; * * @constructor * + * @param {Object} [options={}] - Configuration options for the XR session + * @param {Array<"anchors" | "bounded-floor" | "depth-sensing" | "dom-overlay" | + * "hand-tracking" | "hit-test" | "layers" | "light-estimation" | "local" | + * "local-floor" | "secondary-views" | "unbounded" | "viewer">} [options.requiredFeatures=[]] - Required features + * @param {Object} [options={}] - Configuration options for the XR session + * @param {Array<"anchors" | "bounded-floor" | "depth-sensing" | "dom-overlay" | + * "hand-tracking" | "hit-test" | "layers" | "light-estimation" | "local" | + * "local-floor" | "secondary-views" | "unbounded" | "viewer">} [options.optionalFeatures=[]] - Optional features + * * @property mode {"inline" | "immersive-ar" | "immersive-vr"} WebXR session mode * @property vrDevice {XRDevice} the current VR compatible device * @property vrSession {XRSession} the current VR session @@ -17,7 +26,12 @@ import p5xrInput from './p5xrInput'; * @property curClearColor {Color} background clear color set by global `setVRBackgroundColor` */ export default class p5xr { - constructor() { + constructor(options = {}) { + const { + requiredFeatures = [], + optionalFeatures = [], + } = options; + this.xrDevice = null; this.isVR = null; this.mode = 'inline'; @@ -31,6 +45,9 @@ export default class p5xr { this.gl = null; this.curClearColor = color(256, 255, 255); this.viewer = new p5xrViewer(); + + this.requiredFeatures = requiredFeatures; + this.optionalFeatures = optionalFeatures; } /** @@ -136,6 +153,45 @@ export default class p5xr { } } + /** + * Helper function to reset XR and GL, should be called between + * ending an XR session and starting a new XR session + * @method resetXR + */ + resetXR() { + this.xrDevice = null; + this.xrSession = null; + this.xrRefSpace = null; + this.xrViewerSpace = null; + this.xrHitTestSource = null; + this.gl = null; + this.frame = null; + } + + /** + * `navigator.xr.requestSession()` must be called within a user gesture event. + * @private + * @ignore + */ + __onXRButtonClicked() { + if (this.hasImmersive) { + console.log(`Requesting session with mode: ${this.mode}`); + this.isImmersive = true; + this.resetXR(); + navigator.xr + .requestSession(this.mode, { + requiredFeatures: this.requiredFeatures, + optionalFeatures: this.optionalFeatures, + }) + .then(this.__startSketch.bind(this)) + .catch((error) => { + console.error(`An error occured activating ${this.mode}: ${error}`); + }); + } else { + this.xrButton.hide(); + } + } + /** * This is the method that is attached to the event that announces * availability of a new frame. The next animation frame is requested here, diff --git a/src/p5xr/p5ar/p5ar.js b/src/p5xr/p5ar/p5ar.js index ee281ce..a1112f1 100644 --- a/src/p5xr/p5ar/p5ar.js +++ b/src/p5xr/p5ar/p5ar.js @@ -3,7 +3,9 @@ import ARAnchor from './ARAnchor'; export default class p5ar extends p5xr { constructor() { - super(); + super({ + requiredFeatures: ['local', 'hit-test'], + }); this.mode = 'immersive-ar'; this.canvas = null; this.__createButton(); @@ -93,27 +95,6 @@ export default class p5ar extends p5xr { return new ARAnchor(vec.x, vec.y, vec.z); } - /** - * `device.requestSession()` must be called within a user gesture event. - * @param {XRDevice} - * @private - * @ignore - */ - __onXRButtonClicked() { - navigator.xr - .requestSession('immersive-ar', { - requiredFeatures: ['local', 'hit-test'], - }) - .then( - (session) => { - this.__startSketch(session); - }, - (error) => { - console.log(`${error} unable to request an immersive-ar session.`); - } - ); - } - /** * @private * @ignore diff --git a/src/p5xr/p5vr/p5vr.js b/src/p5xr/p5vr/p5vr.js index c19f189..bbf9f5b 100644 --- a/src/p5xr/p5vr/p5vr.js +++ b/src/p5xr/p5vr/p5vr.js @@ -63,39 +63,6 @@ export default class p5vr extends p5xr { this.__onRequestSession(); } - /** - * Helper function to reset XR and GL, should be called between - * ending an XR session and starting a new XR session - * @method resetXR - */ - resetXR() { - this.xrDevice = null; - this.xrSession = null; - this.xrRefSpace = null; - this.xrViewerSpace = null; - this.xrHitTestSource = null; - this.gl = null; - this.frame = null; - } - - /** - * `navigator.xr.requestSession('immersive-vr')` must be called within a user gesture event. - * @param {XRDevice} - * @private - * @ignore - */ - __onXRButtonClicked() { - if (this.hasImmersive) { - console.log('Requesting session with mode: immersive-vr'); - this.isImmersive = true; - this.resetXR(); - navigator.xr - .requestSession('immersive-vr') - .then(this.__startSketch.bind(this)); - } else { - this.xrButton.hide(); - } - } /** * Requests a reference space and makes the p5's WebGL layer XR compatible. From aac2e078bd79f960013c5bcd87180b9268cfa319 Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Mon, 8 Apr 2024 15:40:24 +0200 Subject: [PATCH 07/11] Consolidated common startsketch and request session into p5xr Removed p5.instance._decrementPreload as it was launching p5 in 2D mode for some reason --- src/p5xr/core/p5xr.js | 112 +++++++++++++++++++++++++++++++++++------- src/p5xr/p5ar/p5ar.js | 38 +------------- src/p5xr/p5vr/p5vr.js | 62 +---------------------- 3 files changed, 98 insertions(+), 114 deletions(-) diff --git a/src/p5xr/core/p5xr.js b/src/p5xr/core/p5xr.js index 0d5d1d6..4e8ced8 100644 --- a/src/p5xr/core/p5xr.js +++ b/src/p5xr/core/p5xr.js @@ -192,6 +192,87 @@ export default class p5xr { } } + /** + * This is where the actual p5 canvas is first created, and + * the GL rendering context is accessed by p5vr. + * The current XRSession also gets a frame of reference and + * base rendering layer.
+ * @param {XRSession} + * @private + * @ignore + */ + __startSketch(session) { + this.xrSession = session; + this.canvas = p5.instance.canvas; + this.canvas.style.visibility = 'visible'; + + if (typeof window.setup === 'function') { + window.setup(); + p5.instance._millisStart = window.performance.now(); + } + // const refSpaceRequest = this.isImmersive ? 'local' : 'viewer'; + // this.xrSession.requestReferenceSpace(refSpaceRequest).then((refSpace) => { + // this.xrRefSpace = refSpace; + // // Inform the session that we're ready to begin drawing. + // this.xrSession.requestAnimationFrame(this.__onXRFrame.bind(this)); + // if (!this.isImmersive) { + // this.xrSession.updateRenderState({ + // baseLayer: new XRWebGLLayer(this.xrSession, this.gl), + // inlineVerticalFieldOfView: 70 * (Math.PI / 180), + // }); + // this.addInlineViewListeners(this.canvas); + // } + // }); + this.__onRequestSession(); + } + + /** + * Requests a reference space and makes the p5's WebGL layer XR compatible. + * @private + * @ignore + */ + __onRequestSession() { + p5.instance._renderer._curCamera.cameraType = 'custom'; + const refSpaceRequest = this.isImmersive ? 'local' : 'viewer'; + + this.gl = this.canvas.getContext(p5.instance.webglVersion); + this.gl + .makeXRCompatible() + .then(() => { + // Use the p5's WebGL context to create a XRWebGLLayer and set it as the + // sessions baseLayer. This allows any content rendered to the layer to + // be displayed on the XRDevice; + this.xrSession.updateRenderState({ + baseLayer: new XRWebGLLayer(this.xrSession, this.gl), + }); + // TODO : need better way to handle feature-specific actions + if (this.requiredFeatures.includes('hit-test')) { + this.xrSession.requestReferenceSpace('viewer').then((refSpace) => { + this.xrViewerSpace = refSpace; + this.xrSession + .requestHitTestSource({ space: this.xrViewerSpace }) + .then((hitTestSource) => { + this.xrHitTestSource = hitTestSource; + }); + }); + } + + // Get a frame of reference, which is required for querying poses. + // 'local' places the initial pose relative to initial location of viewer + // 'viewer' is only for inline experiences and only allows rotation + this.xrSession + .requestReferenceSpace(refSpaceRequest) + .then((refSpace) => { + this.xrRefSpace = refSpace; + // Request initial animation frame + this.xrSession.requestAnimationFrame(this.__onXRFrame.bind(this)); + }); + }) + .catch((e) => { + console.log(e); + }); + } + /** * This is the method that is attached to the event that announces * availability of a new frame. The next animation frame is requested here, @@ -236,6 +317,20 @@ export default class p5xr { this.clearVR(); } + const context = window; + const userCalculate = context.calculate; + if (this.viewer.pose.views.length > 1) { + if (typeof userCalculate === 'function') { + userCalculate(); + } + const now = window.performance.now(); + p5.instance.deltaTime = now - p5.instance._lastFrameTime; + p5.instance._frameRate = 1000.0 / p5.instance.deltaTime; + p5.instance._setProperty('deltaTime', p5.instance.deltaTime); + p5.instance._lastFrameTime = now; + context._setProperty('frameCount', context.frameCount + 1); + } + let i = 0; for (const view of this.viewer.pose.views) { this.viewer.view = view; @@ -279,24 +374,7 @@ export default class p5xr { const context = window; const userSetup = context.setup; const userDraw = context.draw; - const userCalculate = context.calculate; - if (this.isVR) { - if (eyeIndex === 0) { - if (typeof userCalculate === 'function') { - userCalculate(); - } - const now = window.performance.now(); - p5.instance.deltaTime = now - p5.instance._lastFrameTime; - p5.instance._frameRate = 1000.0 / p5.instance.deltaTime; - p5.instance._setProperty('deltaTime', p5.instance.deltaTime); - p5.instance._lastFrameTime = now; - context._setProperty('frameCount', context.frameCount + 1); - } - } else { - // Scale is much smaller in AR - scale(0.01); - } // 2D Mode should use graphics object if (!p5.instance._renderer.isP3D) { console.error('Sketch does not have 3D Renderer'); diff --git a/src/p5xr/p5ar/p5ar.js b/src/p5xr/p5ar/p5ar.js index a1112f1..421e43c 100644 --- a/src/p5xr/p5ar/p5ar.js +++ b/src/p5xr/p5ar/p5ar.js @@ -25,15 +25,11 @@ export default class p5ar extends p5xr { * @ignore */ __startSketch(session) { - this.xrSession = this.xrButton.session = session; - this.xrSession.addEventListener('end', this.__onSessionEnded); + super.__startSketch(session); + if (typeof touchStarted === 'function') { this.xrSession.addEventListener('select', touchStarted); } - this.canvas = p5.instance.canvas; - p5.instance._renderer._curCamera.cameraType = 'custom'; - this.__onRequestSession(); - p5.instance._decrementPreload(); } /** @@ -94,34 +90,4 @@ export default class p5ar extends p5xr { } return new ARAnchor(vec.x, vec.y, vec.z); } - - /** - * @private - * @ignore - */ - __onRequestSession() { - this.gl = this.canvas.getContext(p5.instance.webglVersion, { - xrCompatible: true, - }); - this.gl.makeXRCompatible().then(() => { - this.xrSession.updateRenderState({ - baseLayer: new XRWebGLLayer(this.xrSession, this.gl), - }); - }); - - this.xrSession.requestReferenceSpace('viewer').then((refSpace) => { - this.xrViewerSpace = refSpace; - this.xrSession - .requestHitTestSource({ space: this.xrViewerSpace }) - .then((hitTestSource) => { - this.xrHitTestSource = hitTestSource; - }); - }); - - this.xrSession.requestReferenceSpace('local').then((refSpace) => { - this.xrRefSpace = refSpace; - // Inform the session that we're ready to begin drawing. - this.xrSession.requestAnimationFrame(this.__onXRFrame.bind(this)); - }); - } } diff --git a/src/p5xr/p5vr/p5vr.js b/src/p5xr/p5vr/p5vr.js index bbf9f5b..5bc6885 100644 --- a/src/p5xr/p5vr/p5vr.js +++ b/src/p5xr/p5vr/p5vr.js @@ -38,67 +38,7 @@ export default class p5vr extends p5xr { * @ignore */ __startSketch(session) { - this.xrSession = session; - this.canvas = p5.instance.canvas; - this.canvas.style.visibility = 'visible'; - - this.xrSession.addEventListener('end', this.__onSessionEnded.bind(this)); - if (typeof window.setup === 'function') { - window.setup(); - p5.instance._millisStart = window.performance.now(); - } - const refSpaceRequest = this.isImmersive ? 'local' : 'viewer'; - this.xrSession.requestReferenceSpace(refSpaceRequest).then((refSpace) => { - this.xrRefSpace = refSpace; - // Inform the session that we're ready to begin drawing. - this.xrSession.requestAnimationFrame(this.__onXRFrame.bind(this)); - if (!this.isImmersive) { - this.xrSession.updateRenderState({ - baseLayer: new XRWebGLLayer(this.xrSession, this.gl), - inlineVerticalFieldOfView: 70 * (Math.PI / 180), - }); - this.addInlineViewListeners(this.canvas); - } - }); - this.__onRequestSession(); - } - - - /** - * Requests a reference space and makes the p5's WebGL layer XR compatible. - * @private - * @ignore - */ - __onRequestSession() { - p5.instance._renderer._curCamera.cameraType = 'custom'; - const refSpaceRequest = this.isImmersive ? 'local' : 'viewer'; - - this.gl = this.canvas.getContext(p5.instance.webglVersion); - this.gl - .makeXRCompatible() - .then(() => { - // Get a frame of reference, which is required for querying poses. - // 'local' places the initial pose relative to initial location of viewer - // 'viewer' is only for inline experiences and only allows rotation - this.xrSession - .requestReferenceSpace(refSpaceRequest) - .then((refSpace) => { - this.xrRefSpace = refSpace; - }); - - // Use the p5's WebGL context to create a XRWebGLLayer and set it as the - // sessions baseLayer. This allows any content rendered to the layer to - // be displayed on the XRDevice; - this.xrSession.updateRenderState({ - baseLayer: new XRWebGLLayer(this.xrSession, this.gl), - }); - }) - .catch((e) => { - console.log(e); - }); - - // Request initial animation frame - this.xrSession.requestAnimationFrame(this.__onXRFrame.bind(this)); + super.__startSketch(session); } /** From 7372f612dda82cef45017525c0eff0cdd84d9de6 Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Mon, 8 Apr 2024 16:18:19 +0200 Subject: [PATCH 08/11] Fix tests for launching from constructor --- tests/unit/p5xr/core/p5xr.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/unit/p5xr/core/p5xr.js b/tests/unit/p5xr/core/p5xr.js index bf2cc88..f3497b5 100644 --- a/tests/unit/p5xr/core/p5xr.js +++ b/tests/unit/p5xr/core/p5xr.js @@ -21,7 +21,6 @@ suite('p5xr', function() { suite('init()', function() { test('p5xr.isVR is true for VR sketch', function() { p5xr.instance = new p5vr(); - p5xr.instance.__initVR(); assert.isTrue(p5xr.instance.isVR); p5xr.instance.remove(); }); @@ -30,7 +29,6 @@ suite('p5xr', function() { sinon.spy(window, 'setup'); window.preload = function() { p5xr.instance = new p5vr(); - p5xr.instance.__initVR(); }; myp5.remove(); myp5 = new p5(); @@ -40,17 +38,15 @@ suite('p5xr', function() { }); test('p5xr.__removeLoadingElement() is called', function() { + sinon.spy(p5vr.prototype, '__removeLoadingElement'); p5xr.instance = new p5vr(); - sinon.spy(p5xr.instance, '__removeLoadingElement'); - p5xr.instance.__initVR(); - sinon.assert.called(p5xr.instance.__removeLoadingElement); - p5xr.instance.__removeLoadingElement.restore(); + sinon.assert.called(p5vr.prototype.__removeLoadingElement); + p5vr.prototype.__removeLoadingElement.restore(); p5xr.instance.remove(); }); test('xrButton is set and added in DOM', function() { p5xr.instance = new p5vr(); - p5xr.instance.__initVR(); assert.instanceOf(p5xr.instance.xrButton, p5xrButton); let button = document.querySelector('header button'); assert.equal(button.tagName, 'BUTTON'); @@ -58,11 +54,10 @@ suite('p5xr', function() { }); test('p5xr.__sessionCheck() is called', function() { + sinon.spy(p5vr.prototype, '__sessionCheck'); p5xr.instance = new p5vr(); - sinon.spy(p5xr.instance, '__sessionCheck'); - p5xr.instance.__initVR(); - sinon.assert.called(p5xr.instance.__sessionCheck); - p5xr.instance.__sessionCheck.restore(); + sinon.assert.called(p5vr.prototype.__sessionCheck); + p5vr.prototype.__sessionCheck.restore(); p5xr.instance.remove(); }); }); @@ -71,7 +66,6 @@ suite('p5xr', function() { test('removes p5 loading element from DOM', function() { window.preload = function() { p5xr.instance = new p5vr(); - p5xr.instance.__initVR(); let loading = document.getElementById(window._loadingScreenId); assert.isNull(loading); }; From 0bda0c580fe7e7e9a2cdd6d7058814baffc891db Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Mon, 8 Apr 2024 16:20:32 +0200 Subject: [PATCH 09/11] Hello cube AR example --- examples/ar/hello-cube/example.js | 14 ++++++++++++++ examples/ar/hello-cube/index.html | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 examples/ar/hello-cube/example.js create mode 100644 examples/ar/hello-cube/index.html diff --git a/examples/ar/hello-cube/example.js b/examples/ar/hello-cube/example.js new file mode 100644 index 0000000..79318cf --- /dev/null +++ b/examples/ar/hello-cube/example.js @@ -0,0 +1,14 @@ +function preload() { + createARCanvas(); +} + +function setup() { + describe("A cube waiting to be seen"); +} + +function draw() { + push(); + translate(0, 0, -0.4); + box(0.1, 0.1, 0.1); + pop(); +} diff --git a/examples/ar/hello-cube/index.html b/examples/ar/hello-cube/index.html new file mode 100644 index 0000000..26efec7 --- /dev/null +++ b/examples/ar/hello-cube/index.html @@ -0,0 +1,17 @@ + + + + + + + + + AR EXAMPLE #1 : Hello Cube + + + + +
+ + + From cdf0bb22a995f3f36657a7bd7fcecf0e9e885f4b Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Mon, 8 Apr 2024 17:13:26 +0200 Subject: [PATCH 10/11] ESLint fixes --- src/p5xr/core/p5xr.js | 10 +++++----- src/p5xr/p5ar/p5ar.js | 2 +- src/p5xr/p5vr/p5vr.js | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/p5xr/core/p5xr.js b/src/p5xr/core/p5xr.js index 4e8ced8..f47bd70 100644 --- a/src/p5xr/core/p5xr.js +++ b/src/p5xr/core/p5xr.js @@ -340,7 +340,7 @@ export default class p5xr { viewport.x, viewport.y, viewport.width * scaleFactor, - viewport.height * scaleFactor + viewport.height * scaleFactor, ); this.__updateViewport(viewport); @@ -370,7 +370,7 @@ export default class p5xr { * @private * @ignore */ - __drawEye(eyeIndex) { + __drawEye() { const context = window; const userSetup = context.setup; const userDraw = context.draw; @@ -446,9 +446,9 @@ export default class p5xr { */ printUnsupportedMessage() { console.warn( - 'Your browser/hardware does not work with AR Mode currently. This is' + - ' undergoing heavy development currently.' + - 'You may be able to fix this by enabling WebXR flags in Chrome.' + 'Your browser/hardware does not work with AR Mode currently. This is' + + ' undergoing heavy development currently.' + + 'You may be able to fix this by enabling WebXR flags in Chrome.', ); } diff --git a/src/p5xr/p5ar/p5ar.js b/src/p5xr/p5ar/p5ar.js index 421e43c..6bad9dd 100644 --- a/src/p5xr/p5ar/p5ar.js +++ b/src/p5xr/p5ar/p5ar.js @@ -71,7 +71,7 @@ export default class p5ar extends p5xr { return createVector( pose.transform.position.x, pose.transform.position.y, - pose.transform.position.z + pose.transform.position.z, ); } } diff --git a/src/p5xr/p5vr/p5vr.js b/src/p5xr/p5vr/p5vr.js index 5bc6885..ef10e4b 100644 --- a/src/p5xr/p5vr/p5vr.js +++ b/src/p5xr/p5vr/p5vr.js @@ -75,7 +75,7 @@ export default class p5vr extends p5xr { y: invOrientation[1], z: invOrientation[2], w: invOrientation[3], - } + }, ); return refSpace.getOffsetReferenceSpace(xform); } @@ -130,7 +130,7 @@ export default class p5vr extends p5xr { this.primaryTouch = undefined; this.rotateInlineView( touch.pageX - this.prevTouchX, - touch.pageY - this.prevTouchY + touch.pageY - this.prevTouchY, ); } } @@ -154,7 +154,7 @@ export default class p5vr extends p5xr { if (this.primaryTouch === touch.identifier) { this.rotateInlineView( touch.pageX - this.prevTouchX, - touch.pageY - this.prevTouchY + touch.pageY - this.prevTouchY, ); this.prevTouchX = touch.pageX; this.prevTouchY = touch.pageY; From 1cd719242af21e3a6d0d5e282a9901200c2ed31e Mon Sep 17 00:00:00 2001 From: Tibor Udvari Date: Mon, 29 Jul 2024 15:42:52 +0200 Subject: [PATCH 11/11] Adding back inline session functionality --- src/p5xr/core/p5xr.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/p5xr/core/p5xr.js b/src/p5xr/core/p5xr.js index f47bd70..41dedc3 100644 --- a/src/p5xr/core/p5xr.js +++ b/src/p5xr/core/p5xr.js @@ -43,7 +43,7 @@ export default class p5xr { this.xrHitTestSource = null; this.frame = null; this.gl = null; - this.curClearColor = color(256, 255, 255); + this.curClearColor = color(255, 255, 255); this.viewer = new p5xrViewer(); this.requiredFeatures = requiredFeatures; @@ -210,19 +210,19 @@ export default class p5xr { window.setup(); p5.instance._millisStart = window.performance.now(); } - // const refSpaceRequest = this.isImmersive ? 'local' : 'viewer'; - // this.xrSession.requestReferenceSpace(refSpaceRequest).then((refSpace) => { - // this.xrRefSpace = refSpace; - // // Inform the session that we're ready to begin drawing. - // this.xrSession.requestAnimationFrame(this.__onXRFrame.bind(this)); - // if (!this.isImmersive) { - // this.xrSession.updateRenderState({ - // baseLayer: new XRWebGLLayer(this.xrSession, this.gl), - // inlineVerticalFieldOfView: 70 * (Math.PI / 180), - // }); - // this.addInlineViewListeners(this.canvas); - // } - // }); + const refSpaceRequest = this.isImmersive ? 'local' : 'viewer'; + this.xrSession.requestReferenceSpace(refSpaceRequest).then((refSpace) => { + this.xrRefSpace = refSpace; + // Inform the session that we're ready to begin drawing. + this.xrSession.requestAnimationFrame(this.__onXRFrame.bind(this)); + if (!this.isImmersive) { + this.xrSession.updateRenderState({ + baseLayer: new XRWebGLLayer(this.xrSession, this.gl), + inlineVerticalFieldOfView: 70 * (Math.PI / 180), + }); + this.addInlineViewListeners(this.canvas); + } + }); this.__onRequestSession(); }