Creare un'app di realtà aumentata (AR) utilizzando l'API WebXR Device

1. Prima di iniziare

Questo codelab illustra un esempio di creazione di un'app web AR. Utilizza JavaScript per eseguire il rendering di modelli 3D che sembrano esistere nel mondo reale.

Utilizzi l'API WebXR Device, che combina le funzionalità di AR e realtà virtuale (VR). Ti concentri sulle estensioni AR dell'API WebXR Device per creare una semplice app AR che viene eseguita sul web interattivo.

Che cos'è l'AR?

AR è un termine solitamente utilizzato per descrivere la combinazione di grafica generata al computer con il mondo reale. Nel caso dell'AR basata sullo smartphone, ciò significa posizionare in modo convincente la grafica computerizzata su un feed videocamera in tempo reale. Affinché questo effetto rimanga realistico mentre lo smartphone si muove nel mondo, il dispositivo con AR deve comprendere il mondo in cui si muove e determinare la sua posa (posizione e orientamento) nello spazio 3D. Ciò può includere il rilevamento delle superfici e la stima dell'illuminazione dell'ambiente.

La realtà aumentata è diventata ampiamente utilizzata nelle app dopo il rilascio di ARCore di Google e di ARKit di Apple, sia per i filtri per selfie sia per i giochi basati sulla realtà aumentata.

Cosa creerai

In questo codelab, creerai un'app web che posiziona un modello nel mondo reale utilizzando la realtà aumentata. La tua app sarà in grado di:

  1. Utilizzare i sensori del dispositivo di destinazione per determinare e monitorare la sua posizione e il suo orientamento nel mondo
  2. Eseguire il rendering di un modello 3D composto sopra una visione in diretta della videocamera
  3. Esegui test di rilevamento per posizionare gli oggetti sopra le superfici scoperte nel mondo reale

Obiettivi didattici

  • Come utilizzare l'API WebXR Device
  • Come configurare una scena AR di base
  • Come trovare una superficie utilizzando i test di riscontro AR
  • Come caricare e renderizzare un modello 3D sincronizzato con il feed della videocamera del mondo reale
  • Come eseguire il rendering delle ombre in base al modello 3D

Questo codelab è incentrato sulle API AR. Concetti e blocchi di codice non pertinenti sono trattati solo superficialmente e sono forniti nel codice del repository corrispondente.

Che cosa ti serve

Fai clic su Prova sul tuo dispositivo AR per provare il primo passaggio di questo codelab. Se visualizzi una pagina con il messaggio "Il tuo browser non dispone di funzionalità AR", verifica che sul tuo dispositivo Android sia installato Google Play Services per AR.

2. Configurazione dell'ambiente di sviluppo

Scarica il codice

  1. Fai clic sul seguente link per scaricare tutto il codice di questo codelab sulla tua workstation:

  1. Decomprimi il file ZIP scaricato. Viene estratta una cartella principale (ar-with-webxr-master), che contiene le directory di diversi passaggi di questo codelab, insieme a tutte le risorse necessarie.

Le cartelle step-03 e step-04 contengono lo stato finale desiderato del terzo e del quarto passaggio di questo codelab, nonché il risultato final. Sono presenti a scopo di riferimento.

Esegui tutto il lavoro di codifica nella directory work.

Installare il server web

  1. Puoi utilizzare il tuo web server. Se non ne hai ancora configurato uno, questa sezione descrive in dettaglio come configurare Web Server for Chrome.
    Se non hai ancora installato l'app sulla tua workstation, puoi installarla dal Chrome Web Store.

  1. Dopo aver installato l'app Web Server for Chrome, vai su chrome://apps e fai clic sull'icona del server web:

Icona del server web

Viene visualizzata la seguente finestra di dialogo, che consente di configurare il server web locale:

Configurare il server web Chrome

  1. Fai clic su Scegli cartella e seleziona la cartella ar-with-webxr-master. In questo modo puoi pubblicare il tuo lavoro in corso tramite l'URL evidenziato nella finestra di dialogo del server web (nella sezione URL server web).
  2. Nella sezione Opzioni (richiede riavvio), seleziona la casella di controllo Mostra automaticamente index.html.
  3. Imposta Server web su Arresta, quindi di nuovo su Avviato.Riavviare Chrome Web Server
  4. Verifica che venga visualizzato almeno un URL del server web: http://127.0.0.1:8887, l'URL localhost predefinito.

Configura port forwarding

Configura il dispositivo AR in modo che acceda alla stessa porta della workstation quando visiti localhost:8887.

  1. Nella workstation di sviluppo, vai a chrome://inspect e fai clic su Port forwarding…: chrome://inspect
  2. Utilizza la finestra di dialogo Impostazioni port forwarding per inoltrare la porta 8887 a localhost:8887.
  3. Seleziona la casella di controllo Abilita port forwarding:

Configura port forwarding

Verificare la configurazione

Controlla la tua connessione:

  1. Collega il dispositivo AR alla workstation con un cavo USB.
  2. Sul dispositivo AR in Chrome, inserisci http://localhost:8887 nella barra degli indirizzi. Il dispositivo AR deve inoltrare questa richiesta al server web della workstation di sviluppo. Dovresti visualizzare una directory di file.
  3. Sul dispositivo AR, fai clic su step-03 per caricare il file step-03/index.html nel browser.

Dovresti vedere una pagina contenente un pulsante Avvia la realtà aumentata.

Tuttavia, se visualizzi una pagina di errore Browser non supportato, è probabile che il tuo dispositivo non sia compatibile.

ARCore è supportato

ARCore non è supportato

La connessione al server web dovrebbe ora funzionare con il dispositivo AR.

  1. Fai clic su Avvia realtà aumentata. Potrebbe esserti chiesto di installare ARCore.

Prompt di installazione di ARCore

La prima volta che esegui un'app AR, viene visualizzato un prompt per le autorizzazioni di accesso alla fotocamera.

Chrome richiede le autorizzazioni di accesso alla fotocameraFinestra di dialogo delle autorizzazioni

Quando tutto è pronto, dovresti vedere una scena di cubi sovrapposti a un feed della videocamera. La comprensione della scena migliora man mano che la videocamera analizza una porzione maggiore del mondo, quindi muoversi può contribuire a stabilizzare le cose.

3. Configura WebXR

In questo passaggio, imparerai a configurare una sessione WebXR e una scena AR di base. La pagina HTML viene fornita con lo stile CSS e JavaScript per abilitare la funzionalità AR di base. In questo modo la procedura di configurazione viene velocizzata e il codelab può concentrarsi sulle funzionalità AR.

La pagina HTML

Puoi integrare un'esperienza AR in una pagina web tradizionale utilizzando le tecnologie web esistenti. In questa esperienza, utilizzi un canvas di rendering a schermo intero, quindi il file HTML non deve essere troppo complesso.

Le funzionalità AR richiedono un gesto dell'utente per essere avviate, pertanto sono presenti alcuni componenti Material Design per visualizzare il pulsante Avvia AR e il messaggio relativo al browser non supportato.

Il file index.html già presente nella directory work dovrebbe avere il seguente aspetto. Si tratta di un sottoinsieme dei contenuti effettivi, quindi non copiare questo codice nel tuo file.

<!-- Don't copy this code into your file! -->
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Building an augmented reality application with the WebXR Device API</title>
    <link rel="stylesheet" href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css">
    <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>

    <!-- three.js -->
    <script src="https://unpkg.com/three@0.123.0/build/three.js"></script>
    <script src="https://unpkg.com/three@0.123.0/examples/js/loaders/GLTFLoader.js"></script>

    <script src="../shared/utils.js"></script>
    <script src="app.js"></script>
  </head>
  <body>
  <!-- Information about AR removed for brevity. -->

  <!-- Starting an immersive WebXR session requires user interaction. Start the WebXR experience with a simple button. -->
  <a onclick="activateXR()" class="mdc-button mdc-button--raised mdc-button--accent">
    Start augmented reality
  </a>

</body>
</html>

Apri il codice JavaScript della chiave

Il punto di partenza della tua app è in app.js. Questo file fornisce alcuni codici standard per la configurazione di un'esperienza AR.

La tua directory di lavoro include già il codice dell'app (app.js).

Controllare il supporto di WebXR e AR

Prima che un utente possa lavorare con la AR, verifica l'esistenza di navigator.xr e delle funzionalità XR necessarie. L'oggetto navigator.xr è il punto di accesso per l'API WebXR Device, quindi dovrebbe esistere se il dispositivo è compatibile. Inoltre, verifica che la modalità sessione "immersive-ar" sia supportata.

Se tutto va bene, facendo clic sul pulsante Enter augmented reality (Entra nella realtà aumentata) si tenta di creare una sessione XR. In caso contrario, viene chiamato onNoXRDevice() (in shared/utils.js), che visualizza un messaggio che indica la mancanza di supporto AR.

Questo codice è già presente in app.js, quindi non è necessario apportare modifiche.

(async function() {
  if (navigator.xr && await navigator.xr.isSessionSupported("immersive-ar")) {
    document.getElementById("enter-ar").addEventListener("click", activateXR)
  } else {
    onNoXRDevice();
  }
})();

Richiedere un XRSession

Quando fai clic su Inserisci realtà aumentata, il codice chiama activateXR(). In questo modo si avvia l'esperienza AR.

  1. Trova la funzione activateXR() in app.js. Alcuni codici sono stati omessi:
activateXR = async () => {
  // Initialize a WebXR session using "immersive-ar".
  this.xrSession = /* TODO */;

  // Omitted for brevity
}

Il punto di accesso a WebXR è tramite XRSystem.requestSession(). Utilizza la modalità immersive-ar per consentire la visualizzazione dei contenuti sottoposti a rendering in un ambiente reale.

  1. Inizializza this.xrSession utilizzando la modalità "immersive-ar":
activateXR = async () => {
  // Initialize a WebXR session using "immersive-ar".
  this.xrSession = await navigator.xr.requestSession("immersive-ar");

  // ...
}

Inizializza un XRReferenceSpace

Un XRReferenceSpace descrive il sistema di coordinate utilizzato per gli oggetti all'interno del mondo virtuale. La modalità 'local' è più adatta a un'esperienza AR, con uno spazio di riferimento che ha un'origine vicino allo spettatore e un tracciamento stabile.

Inizializza this.localReferenceSpace in onSessionStarted() con il seguente codice:

this.localReferenceSpace = await this.xrSession.requestReferenceSpace("local");

Definire un ciclo di animazione

  1. Utilizza requestAnimationFrame di XRSession per avviare un ciclo di rendering, simile a window.requestAnimationFrame.

Su ogni frame, onXRFrame viene chiamato con un timestamp e un XRFrame.

  1. Completa l'implementazione di onXRFrame. Quando viene disegnato un frame, metti in coda la richiesta successiva aggiungendo:
// Queue up the next draw request.
this.xrSession.requestAnimationFrame(this.onXRFrame);
  1. Aggiungi il codice per configurare l'ambiente grafico. Aggiungi in fondo a onXRFrame:
// Bind the graphics framebuffer to the baseLayer's framebuffer.
const framebuffer = this.xrSession.renderState.baseLayer.framebuffer;
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
this.renderer.setFramebuffer(framebuffer);
  1. Per determinare la posa dello spettatore, utilizza XRFrame.getViewerPose(). Questo XRViewerPose descrive la posizione e l'orientamento del dispositivo nello spazio. Contiene anche un array di XRView, che descrive ogni punto di vista da cui deve essere eseguito il rendering della scena per essere visualizzata correttamente sul dispositivo corrente. Mentre la VR stereoscopica ha due visualizzazioni (una per occhio), i dispositivi AR ne hanno solo una.
    Le informazioni in pose.views vengono utilizzate più comunemente per configurare la matrice di visualizzazione e la matrice di proiezione della videocamera virtuale. Questa impostazione influisce sulla disposizione della scena in 3D. Una volta configurata la videocamera, è possibile eseguire il rendering della scena.
  2. Aggiungi in fondo a onXRFrame:
// Retrieve the pose of the device.
// XRFrame.getViewerPose can return null while the session attempts to establish tracking.
const pose = frame.getViewerPose(this.localReferenceSpace);
if (pose) {
  // In mobile AR, we only have one view.
  const view = pose.views[0];

  const viewport = this.xrSession.renderState.baseLayer.getViewport(view);
  this.renderer.setSize(viewport.width, viewport.height);

  // Use the view's transform matrix and projection matrix to configure the THREE.camera.
  this.camera.matrix.fromArray(view.transform.matrix);
  this.camera.projectionMatrix.fromArray(view.projectionMatrix);
  this.camera.updateMatrixWorld(true);

  // Render the scene with THREE.WebGLRenderer.
  this.renderer.render(this.scene, this.camera);
}

Testalo

Esegui l'app; sul dispositivo di sviluppo, visita work/index.html. Dovresti vedere il feed della videocamera con cubi che fluttuano nello spazio e la cui prospettiva cambia man mano che sposti il dispositivo. Il monitoraggio migliora man mano che ti muovi, quindi esplora le impostazioni più adatte a te e al tuo dispositivo.

Se hai problemi con l'esecuzione dell'app, consulta le sezioni Introduzione e Configurare l'ambiente di sviluppo.

4. Aggiungere un reticolo di targeting

Una volta configurata una scena AR di base, è il momento di iniziare a interagire con il mondo reale utilizzando un test di riscontro. In questa sezione, programmerai un test di hit e lo utilizzerai per trovare una superficie nel mondo reale.

Comprendere un test di hit

Un test di intercettazione è in genere un modo per tracciare una linea retta da un punto nello spazio in una determinata direzione e determinare se interseca oggetti di interesse. In questo esempio, punti il dispositivo verso una posizione nel mondo reale. Immagina un raggio che parte dalla fotocamera del tuo dispositivo e si dirige dritto nel mondo fisico di fronte a te.

L'API WebXR Device ti consente di sapere se questo raggio ha intersecato oggetti nel mondo reale, in base alle funzionalità AR sottostanti e alla comprensione del mondo.

Messaggio esplicativo del test di riscontro

Richiedere un XRSession con funzionalità aggiuntive

Per eseguire test di impatto, sono necessarie funzionalità aggiuntive quando si richiede XRSession.

  1. In app.js, individua navigator.xr.requestSession.
  2. Aggiungi le funzionalità "hit-test" e "dom-overlay" come requiredFeature nel seguente modo:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
  requiredFeatures: ["hit-test", "dom-overlay"]
});
  1. Configura l'overlay DOM. Sovrapponi l'elemento document.body alla visualizzazione della videocamera AR nel seguente modo:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
  requiredFeatures: ["hit-test", "dom-overlay"],
  domOverlay: { root: document.body }
});

Aggiungere un prompt di movimento

ARCore funziona meglio quando è stata creata una comprensione adeguata dell'ambiente. Ciò si ottiene tramite un processo chiamato localizzazione e mappatura simultanea (SLAM), in cui vengono utilizzati punti caratteristici visivamente distinti per calcolare una variazione delle caratteristiche di posizione e ambiente.

Utilizza il "dom-overlay" del passaggio precedente per visualizzare un messaggio di movimento nella parte superiore dello stream della videocamera.

Aggiungi un <div> a index.html con ID stabilization. Questo <div> mostra agli utenti un'animazione che rappresenta lo stato di stabilizzazione e li invita a muoversi con il dispositivo per migliorare la procedura SLAM. Viene visualizzato quando l'utente si trova in AR e nascosto quando il reticolo trova una superficie, controllato dalle classi <body>.

  <div id="stabilization"></div>

</body>
</html>

Aggiungere un reticolo

Utilizza un reticolo per indicare la posizione verso cui è puntata la visuale del dispositivo.

  1. In app.js, sostituisci la chiamata DemoUtils.createCubeScene() in setupThreeJs() con un Three.Scene() vuoto.
setupThreeJs() {
  // ...

  // this.scene = DemoUtils.createCubeScene();
  this.scene = DemoUtils.createLitScene();
}
  1. Riempi la nuova scena con un oggetto che rappresenti il punto di collisione. La classe Reticle fornita gestisce il caricamento del modello di reticolo in shared/utils.js.
  2. Aggiungi Reticle alla scena in setupThreeJs():
setupThreeJs() {
  // ...

  // this.scene = DemoUtils.createCubeScene();
  this.scene = DemoUtils.createLitScene();
  this.reticle = new Reticle();
  this.scene.add(this.reticle);
}

Per eseguire un test di hit, utilizzi un nuovo XRReferenceSpace. Questo spazio di riferimento indica un nuovo sistema di coordinate dal punto di vista del visualizzatore per creare un raggio allineato alla direzione di visualizzazione. Questo sistema di coordinate viene utilizzato in XRSession.requestHitTestSource(), che può calcolare i test di hit.

  1. Aggiungi quanto segue a onSessionStarted() in app.js:
async onSessionStarted() {
  // ...

  // Setup an XRReferenceSpace using the "local" coordinate system.
  this.localReferenceSpace = await this.xrSession.requestReferenceSpace("local");

  // Add these lines:
  // Create another XRReferenceSpace that has the viewer as the origin.
  this.viewerSpace = await this.xrSession.requestReferenceSpace("viewer");
  // Perform hit testing using the viewer as origin.
  this.hitTestSource = await this.xrSession.requestHitTestSource({ space: this.viewerSpace });

  // ...
}
  1. Utilizzando questo hitTestSource, esegui un test di riscontro ogni frame:
    • Se non vengono visualizzati risultati per il test di hit, ARCore non ha avuto abbastanza tempo per comprendere l'ambiente. In questo caso, chiedi all'utente di spostare il dispositivo utilizzando la stabilizzazione <div>.
    • Se vengono visualizzati risultati, sposta il reticolo in quella posizione.
  2. Modifica onXRFrame per spostare il reticolo:
onXRFrame = (time, frame) => {
  // ... some code omitted ...
  this.camera.updateMatrixWorld(true);

  // Add the following:
  const hitTestResults = frame.getHitTestResults(this.hitTestSource);

  if (!this.stabilized && hitTestResults.length > 0) {
    this.stabilized = true;
    document.body.classList.add("stabilized");
  }
  if (hitTestResults.length > 0) {
    const hitPose = hitTestResults[0].getPose(this.localReferenceSpace);

    // update the reticle position
    this.reticle.visible = true;
    this.reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z)
    this.reticle.updateMatrixWorld(true);
  }
  // More code omitted.
}

Aggiungere un comportamento al tocco dello schermo

Un XRSession può generare eventi in base all'interazione dell'utente tramite l'evento select, che rappresenta l'azione principale. In WebXR sui dispositivi mobili, l'azione principale è un tocco dello schermo.

  1. Aggiungi un listener di eventi select in fondo a onSessionStarted:
this.xrSession.addEventListener("select", this.onSelect);

In questo esempio, un tocco dello schermo fa sì che un girasole venga posizionato sul reticolo.

  1. Crea un'implementazione per onSelect nella classe App:
onSelect = () => {
  if (window.sunflower) {
    const clone = window.sunflower.clone();
    clone.position.copy(this.reticle.position);
    this.scene.add(clone);
  }
}

Testare l'app

Hai creato un reticolo che puoi puntare utilizzando il tuo dispositivo tramite test di precisione. Quando tocchi lo schermo, dovresti essere in grado di posizionare un girasole nella posizione indicata dal reticolo.

  1. Quando esegui l'app, dovresti vedere un reticolo che traccia la superficie del pavimento. In caso contrario, prova a guardarti lentamente intorno con lo smartphone.
  2. Quando vedi il reticolo, toccalo. Sopra deve essere posizionato un girasole. Potresti dover muoverti un po' in modo che la piattaforma AR sottostante possa rilevare meglio le superfici nel mondo reale. La scarsa illuminazione e le superfici senza caratteristiche riducono la qualità della comprensione della scena e aumentano la possibilità che non venga trovato alcun risultato. Se riscontri problemi, consulta il codice step-04/app.js per visualizzare un esempio funzionante di questo passaggio.

5. Aggiungere ombre

La creazione di una scena realistica prevede elementi come l'illuminazione e le ombre corrette sugli oggetti digitali, che aggiungono realismo e immersione nella scena.

L'illuminazione e le ombre vengono gestite da three.js. Puoi specificare quali luci devono proiettare ombre, quali materiali devono ricevere e renderizzare queste ombre e quali mesh possono proiettare ombre. La scena di questa app contiene una luce che proietta un'ombra e una superficie piana per il rendering delle sole ombre.

  1. Attiva le ombre su three.js WebGLRenderer. Dopo aver creato il renderer, imposta i seguenti valori nel relativo shadowMap:
setupThreeJs() {
  ...
  this.renderer = new THREE.WebGLRenderer(...);
  ...
  this.renderer.shadowMap.enabled = true;
  this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  ...
}

La scena di esempio creata in DemoUtils.createLitScene() contiene un oggetto denominato shadowMesh, una superficie piatta e orizzontale che esegue il rendering solo delle ombre. Inizialmente,questa superficie ha una posizione Y di 10.000 unità. Una volta posizionato un girasole, sposta shadowMesh in modo che si trovi alla stessa altezza della superficie del mondo reale, in modo che l'ombra del fiore venga visualizzata sopra il terreno del mondo reale.

  1. In onSelect, dopo aver aggiunto clone alla scena, aggiungi il codice per riposizionare il piano dell'ombra:
onSelect = () => {
  if (window.sunflower) {
    const clone = window.sunflower.clone();
    clone.position.copy(this.reticle.position);
    this.scene.add(clone);

    const shadowMesh = this.scene.children.find(c => c.name === "shadowMesh");
    shadowMesh.position.y = clone.position.y;
  }
}

Testalo

Quando posizioni un girasole, dovresti vederne l'ombra. Se riscontri problemi, consulta il codice final/app.js per visualizzare un esempio funzionante di questo passaggio.

6. Risorse aggiuntive

Complimenti! Hai raggiunto la fine di questo codelab sulla AR con WebXR.

Scopri di più