La realtà virtuale arriva sul Web

Alcuni concetti di base per prepararti a una serie di esperienze immersive: realtà virtuale, realtà aumentata e tutto il resto.

Joe Medley
Joe Medley

Le esperienze immersive sono arrivate sul web in Chrome 79. L'API WebXR Device ha portato la realtà virtuale, mentre il supporto per la realtà aumentata è arrivato in Chrome 81. Un aggiornamento dell'API GamePad estende l'utilizzo avanzato dei controlli alla realtà virtuale. Altri browser supporteranno presto queste specifiche, tra cui Firefox Reality, Oculus Browser, Edge e il browser Helio di Magic Leap.

Questo articolo inizia una serie sul web immersivo. Questa puntata tratta la configurazione di un'applicazione WebXR di base, nonché l'accesso e l'uscita da una sessione XR. Gli articoli successivi tratteranno il ciclo di frame (il cavallo di battaglia dell'esperienza WebXR), le specifiche della realtà aumentata e l'API WebXR Hit Test, un mezzo per rilevare le superfici in una sessione AR. Se non diversamente indicato, tutto ciò che tratto in questo e nei successivi articoli si applica sia alla realtà aumentata che alla realtà virtuale.

Che cos'è il web immersivo?

Sebbene utilizziamo due termini per descrivere le esperienze immersive, realtà aumentata e realtà virtuale, molti le considerano uno spettro che va dalla realtà completa al virtuale completo, con gradi di immersione intermedi. La "X" in XR ha lo scopo di riflettere questo pensiero, essendo una sorta di variabile algebrica che rappresenta qualsiasi cosa nello spettro delle esperienze immersive.

Un grafico che illustra lo spettro delle esperienze visive dalla realtà completa a quella completamente immersiva.
Lo spettro delle esperienze immersive

Ecco alcuni esempi di esperienze immersive:

  • Giochi
  • Video a 360°
  • Video 2D (o 3D) tradizionali presentati in ambienti immersivi
  • Acquisto di una casa
  • Visualizzazione dei prodotti in casa prima dell'acquisto
  • Arte immersiva
  • Qualcosa di interessante a cui nessuno ha ancora pensato

Concetti e utilizzo

Spiegherò alcuni concetti di base sull'utilizzo dell'API WebXR Device. Se hai bisogno di maggiori dettagli di quelli che ho fornito, consulta gli esempi WebXR del gruppo di lavoro Immersive Web o i materiali di riferimento in crescita di MDN. Se hai familiarità con le prime versioni dell'API WebXR Device, dovresti dare un'occhiata a tutto questo materiale. Sono state apportate modifiche.

Il codice in questo articolo si basa sull'esempio di base del gruppo di lavoro Immersive Web (demo, origine), ma è stato modificato per chiarezza e semplicità.

Parte della creazione della specifica WebXR è stata l'elaborazione di misure di sicurezza e privacy per proteggere gli utenti. Di conseguenza, le implementazioni devono rispettare determinati requisiti. Una pagina web o un'app deve essere attiva e avere lo stato attivo prima di poter richiedere qualsiasi informazione sensibile allo spettatore. Le pagine web o le app devono essere pubblicate tramite HTTPS. L'API stessa è progettata per proteggere le informazioni ottenute da sensori e fotocamere, di cui ha bisogno per funzionare.

Richiedere una sessione

Per accedere a una sessione XR è necessaria un'attivazione dall'utente. Per ottenerlo, utilizza il rilevamento delle funzionalità per testare XRSystem (tramite navigator.xr) ed effettua una chiamata a XRSystem.isSessionSupported(). Tieni presente che nelle versioni 79 e 80 di Chrome l' XRSystem oggetto era chiamato XR.

Nell'esempio seguente, ho indicato che voglio una sessione di realtà virtuale con il tipo di sessione 'immersive-vr'. Gli altri tipi di sessione sono 'immersive-ar' e 'inline'. Una sessione in linea serve per presentare i contenuti all'interno di HTML e viene utilizzata principalmente per i contenuti teaser. L'esempio di sessione AR immersiva lo dimostra. Lo spiegherò in un articolo successivo.

Una volta che so che le sessioni di realtà virtuale sono supportate, attivo un pulsante che mi consente di acquisire un gesto dell'utente.

if (navigator.xr) {
  const supported = await navigator.xr.isSessionSupported('immersive-vr');
  if (supported) {
    xrButton.addEventListener('click', onButtonClicked);
    xrButton.textContent = 'Enter VR';
    xrButton.enabled = supported; // supported is Boolean
  }
}

Dopo aver attivato il pulsante, attendo un evento di clic e poi richiedo una sessione.

let xrSession = null;
function onButtonClicked() {
  if (!xrSession) {
    navigator.xr.requestSession('immersive-vr')
    .then((session) => {
      xrSession = session;
      xrButton.textContent = 'Exit XR';
      onSessionStarted(xrSession);
    });
  } else {
    xrSession.end();
  }
}

Nota la gerarchia degli oggetti in questo codice. Si sposta da navigator a xr a un'istanza XRSession. Nelle prime versioni dell'API, uno script doveva richiedere un dispositivo prima di richiedere una sessione. Ora, il dispositivo viene acquisito implicitamente.

Accedere a una sessione

Dopo aver ottenuto una sessione, devo avviarla e accedervi. Ma prima, devo configurare alcune cose. Una sessione ha bisogno di un gestore di eventi onend in modo che l'app o la pagina web possa essere reimpostata quando l'utente esce.

Avrò anche bisogno di un elemento <canvas> su cui disegnare la mia scena. Deve essere un WebGLRenderingContext o WebGL2RenderingContextcompatibile con XR. Tutti i disegni vengono eseguiti utilizzando questi elementi o un framework basato su WebGL come Three.js.

Ora che ho un posto dove disegnare, ho bisogno di una fonte di contenuti su cui disegnare. A questo scopo, creo un'istanza di XRWebGLLayer. La associo al canvas chiamando XRSession.updateRenderState().

Una volta che sono in una sessione, ho bisogno di un modo per determinare dove si trovano le cose nella realtà virtuale. Avrò bisogno di uno spazio di riferimento. Uno spazio di riferimento 'local-floor' è uno in cui l'origine si trova vicino allo spettatore e l'asse y è 0 a livello del pavimento e non dovrebbe spostarsi. Esistono altri tipi di spazi di riferimento , ma questo è un argomento più complicato di quanto possa trattare qui. Salvo lo spazio di riferimento in una variabile perché mi servirà quando disegno sullo schermo.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  let canvas = document.createElement('canvas');
  webGLRenContext = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(xrSession, webGLRenContext)
  });

  xrSession.requestReferenceSpace('local-floor')
  .then((refSpace) => {
    xrRefSpace = refSpace;
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

Dopo aver ottenuto uno spazio di riferimento, chiamo XRSession.requestAnimationFrame(). Questo è l'inizio della presentazione dei contenuti virtuali, che viene eseguita nel ciclo di frame.

Eseguire un ciclo di frame

Il ciclo di frame è un ciclo infinito controllato dall'user agent in cui i contenuti vengono disegnati ripetutamente sullo schermo. I contenuti vengono disegnati in blocchi discreti chiamati frame. La successione dei frame crea l'illusione del movimento. Per le applicazioni VR, i frame al secondo possono variare da 60 a 144. La realtà aumentata per Android viene eseguita a 30 frame al secondo. Il codice non deve presupporre una frequenza fotogrammi specifica.

La procedura di base per il ciclo di frame è la seguente:

  1. Chiama XRSession.requestAnimationFrame(). In risposta, l'user agent richiama XRFrameRequestCallback, che è definito da te.
  2. All'interno della funzione di callback:
    1. Chiama di nuovo XRSession.requestAnimationFrame().
    2. Ottieni la posa dello spettatore.
    3. Passa ("lega") WebGLFramebuffer da XRWebGLLayer a WebGLRenderingContext.
    4. Esegui l'iterazione su ogni oggetto XRView, recuperando il relativo XRViewport da XRWebGLLayer e passandolo a WebGLRenderingContext.
    5. Disegna qualcosa nel framebuffer.

Il resto di questo articolo descrive il passaggio 1 e parte del passaggio 2, la configurazione e la chiamata di XRFrameRequestCallback. Gli elementi rimanenti del passaggio 2 sono trattati nella parte II.

XRFrameRequestCallback

XRFrameRequestCallback è definito da te. Accetta due parametri: un DOMHighResTimeStamp e un'istanza XRFrame. L'oggetto XRFrame fornisce le informazioni necessarie per eseguire il rendering di un singolo frame sul display. L'argomento DOMHighResTimeStamp è per un utilizzo futuro.

Prima di fare qualsiasi altra cosa, richiedo il frame di animazione successivo. Come indicato in precedenza, la tempistica dei frame è determinata dall'user agent in base all'hardware sottostante. La richiesta del frame successivo garantisce che il ciclo di frame continui se si verifica un errore durante la callback.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  // Render a frame.
}

A questo punto, è il momento di disegnare qualcosa per lo spettatore. Questo è un argomento per la parte II. Prima di andare lì, ti mostro come terminare una sessione.

Terminare la sessione

Una sessione immersiva può terminare per diversi motivi, tra cui la terminazione tramite il tuo codice tramite una chiamata a XRSession.end(). Altre cause includono la disconnessione delle cuffie o un'altra applicazione che ne assume il controllo. Per questo motivo, un'applicazione ben funzionante deve monitorare l'evento end. Quando si verifica, elimina la sessione e gli oggetti di rendering correlati. Non è possibile riprendere una sessione immersiva terminata. Per rientrare nell'esperienza immersiva, la mia app deve avviare una nuova sessione.

Ricorda che in Accesso a una sessione, durante la configurazione, ho aggiunto un onend gestore di eventi.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);
  // More setup…
}

All'interno del gestore di eventi, ripristina lo stato dell'app prima che l'utente acceda a una sessione.

function onSessionEnded(event) {
  xrSession = null;
  xrButton.textContent = 'Enter VR';
}

Conclusione

Non ho spiegato tutto ciò che ti serve per scrivere un'applicazione Web XR o AR. Spero di averti fornito informazioni sufficienti per iniziare a comprendere il codice e per iniziare a sperimentare. Nell'articolo successivo, spiegherò il ciclo di frame, in cui i contenuti vengono disegnati sullo schermo.