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.

Utilizza 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 funzioni sul web interattivo.

Che cos'è l'AR?

L'AR è un termine solitamente utilizzato per descrivere la combinazione di grafica computerizzata con il mondo reale. Nel caso dell'AR basata su telefono, ciò significa posizionare in modo convincente la grafica del computer su un feed della videocamera in diretta. Affinché questo effetto sia realistico mentre lo smartphone si sposta per il mondo, il dispositivo abilitato per l'AR deve comprendere il mondo attraverso il quale 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 di uso comune nelle app dopo il rilascio di ARCore di Google e di ARKit di Apple, che si tratti di filtri per selfie o giochi basati sull'AR.

Cosa creerai

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

  1. Utilizza 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 composito sopra una visualizzazione in diretta della videocamera
  3. Esegui test di corrispondenza 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 usando i test degli hit AR
  • Come caricare ed eseguire il rendering di 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 link seguente per scaricare tutto il codice di questo codelab sulla tua workstation:

  1. Estrai il file ZIP scaricato. Viene scompattata una cartella principale (ar-with-webxr-master), che contiene le directory di diversi passaggi di questo codelab, oltre 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 disponibili come riferimento.

Esegui tutte le operazioni di programmazione nella directory work.

Installa server web

  1. Puoi utilizzare il tuo server web. Se non ne hai ancora uno configurato, questa sezione spiega come configurare il server web per Chrome.
    Se l'app non è ancora installata sulla tua workstation, puoi installarla dal Chrome Web Store.

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

Icona server web

Viene visualizzata questa finestra di dialogo, che ti consente di configurare il server web locale:

Configura 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 del server web).
  2. In Opzioni (è necessario riavviare), seleziona la casella di controllo Mostra automaticamente index.html.
  3. Imposta Server web su Arresta, quindi torna su Avvio.Riavviare il server web Chrome
  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 sulla tua workstation quando visiti localhost:8887.

  1. Nella workstation di sviluppo, vai a chrome://inspect e fai clic su Inoltro di porta…: chrome://inspect
  2. Utilizza la finestra di dialogo Impostazioni di port forwarding per inoltrare la porta 8887 a localhost:8887.
  3. Seleziona la casella di controllo Attiva l'inoltro delle porte:

Configura port forwarding

Verificare la configurazione

Verifica la 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 dovrebbe inoltrare questa richiesta al server web della workstation di sviluppo. Dovresti vedere 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 viene visualizzata la 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. È possibile che ti venga richiesto di installare ARCore.

Richiesta di installazione di ARCore

La prima volta che esegui un'app AR viene visualizzata una richiesta di autorizzazione della fotocamera.

Chrome richiede le autorizzazioni di accesso alla fotocameraFinestra di dialogo Autorizzazioni

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

3. Configurare WebXR

In questo passaggio, imparerai a configurare una sessione WebXR e una scena AR di base. La pagina HTML è fornita con stili CSS e JavaScript per attivare la funzionalità AR di base. In questo modo la procedura di configurazione viene accelerata, consentendo al codelab di concentrarsi sulle funzionalità AR.

La pagina HTML

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

Per avviare le funzionalità AR è necessario un gesto dell'utente, perciò esistono alcuni componenti Material Design per la visualizzazione del pulsante Avvia AR e del messaggio del 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; non copiare questo codice nel 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 del codice boilerplate per la configurazione di un'esperienza AR.

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

Verificare il supporto di WebXR e AR

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

Se tutto va bene, facendo clic sul pulsante Entra nella realtà aumentata viene tentata la creazione di una sessione XR. In caso contrario, viene chiamato onNoXRDevice() (in shared/utils.js), che mostra un messaggio che indica la mancanza del 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 Entra nella realtà aumentata, il codice chiama activateXR(). Viene avviata 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 visualizzati 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");

  // ...
}

Inizializzare un XRReferenceSpace

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

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

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

Definire un loop di animazione

  1. Usa l'elemento requestAnimationFrame di XRSession per avviare un loop di rendering, simile a window.requestAnimationFrame.

In ogni fotogramma, 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 visualizzata la scena per essere visualizzata correttamente sul dispositivo corrente. Mentre la realtà virtuale stereoscopica ha due visualizzazioni (una per ogni occhio), i dispositivi AR hanno una sola visualizzazione.
    Le informazioni in pose.views vengono utilizzate più comunemente per configurare la matrice di visualizzazione e la matrice di proiezione della videocamera virtuale. Questo influisce sulla disposizione della scena in 3D. Una volta configurata la videocamera, la scena può essere visualizzata.
  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);
}

Testa

Esegui l'app; visita work/index.html sul dispositivo di sviluppo. Dovresti vedere il feed della videocamera con dei cubi che fluttuano nello spazio la cui prospettiva cambia mentre muovi il dispositivo. Il monitoraggio migliora man mano che ti sposti, quindi scopri cosa funziona per te e per il tuo dispositivo.

Se hai problemi a eseguire l'app, consulta le sezioni Introduzione e Configurare l'ambiente di sviluppo.

4. Aggiungere un mirino di targeting

Dopo aver configurato una scena AR di base, è il momento di iniziare a interagire con il mondo reale utilizzando un test di hit. In questa sezione, programmi un test di corrispondenza e lo utilizzi per trovare una superficie nel mondo reale.

Informazioni su un test di hit

In genere, un test di corrispondenza è 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, indirizzi il dispositivo verso una posizione nel mondo reale. Immagina un raggio che parte dalla fotocamera del dispositivo e arriva direttamente nel mondo fisico di fronte.

L'API WebXR Device ti consente di sapere se questo raggio ha intersecato oggetti nel mondo reale, determinato dalle funzionalità AR sottostanti e dalla comprensione del mondo.

Esempio di hit test

Richiedi un XRSession con funzionalità extra

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

  1. In app.js, individua navigator.xr.requestSession.
  2. Aggiungi le funzionalità "hit-test" e "dom-overlay" come requiredFeature come segue:
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 fotocamera AR in questo modo:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
  requiredFeatures: ["hit-test", "dom-overlay"],
  domOverlay: { root: document.body }
});

Aggiungere un prompt relativo al movimento

ARCore funziona al meglio quando è stata acquisita una conoscenza adeguata dell'ambiente. Questo si ottiene attraverso un processo chiamato SLAM (Localization and Mapping simultaneo) in cui punti di caratteristiche visivamente distinti vengono utilizzati per calcolare una variazione delle caratteristiche di località e ambiente.

Usa l'"dom-overlay" del passaggio precedente per visualizzare una richiesta di movimento sopra lo 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 il processo SLAM. Viene visualizzato quando l'utente si trova in AR e viene nascosto quando il reticolo trova una superficie controllata da <body> classi.

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

</body>
</html>

Aggiungere un mirino

Utilizza un reticolo per indicare la posizione verso cui punta il campo visivo del dispositivo.

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

  // this.scene = DemoUtils.createCubeScene();
  this.scene = DemoUtils.createLitScene();
}
  1. Inserisci nella nuova scena un oggetto che rappresenti il punto di collisione. La classe Reticle fornita gestisce il caricamento del modello di mirino 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 degli hit, utilizza un nuovo XRReferenceSpace. Questo spazio di riferimento indica un nuovo sistema di coordinate dal punto di vista dell'utente per creare un raggio allineato alla direzione di visualizzazione. Questo sistema di coordinate viene utilizzato in XRSession.requestHitTestSource(), che può calcolare i test di corrispondenza.

  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 corrispondenza in ogni frame:
    • Se non ci sono risultati per il test di corrispondenza, significa che ARCore non ha avuto tempo sufficiente per comprendere l'ambiente. In questo caso, chiedi all'utente di spostare il dispositivo utilizzando la stabilizzazione <div>.
    • Se ci sono risultati, sposta il reticolo in quella posizione.
  2. Modifica onXRFrame per spostare il mirino:
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ò emettere 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 sullo schermo.

  1. Aggiungi un gestore di eventi select nella parte inferiore di onSessionStarted:
this.xrSession.addEventListener("select", this.onSelect);

In questo esempio, un tocco sullo schermo fa sì che un girasole venga posizionato nel mirino.

  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);
  }
}

Testa l'app

Hai creato un mirino che puoi puntare utilizzando il tuo dispositivo con i test di corrispondenza. Quando tocchi lo schermo, dovresti riuscire a posizionare un girasole nella posizione indicata dal mirino.

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

5. Aggiungere ombre

La creazione di una scena realistica prevede elementi come illuminazione e ombre adeguate sugli oggetti digitali che aggiungono realismo e coinvolgimento alla scena.

L'illuminazione e le ombre vengono gestite da three.js. Puoi specificare quali luci devono proiettare ombre, quali materiali devono riceverle e visualizzarle 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 solo delle ombre.

  1. Attiva le ombre su three.js WebGLRenderer. Dopo aver creato il visualizzatore, imposta i seguenti valori su 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 chiamato shadowMesh, una superficie piatta orizzontale che mostra solo ombre. Questa superficie ha inizialmente una posizione Y di 10.000 unità. Dopo aver posizionato un girasole, sposta il shadowMesh in modo che abbia la stessa altezza della superficie del mondo reale, in modo che l'ombra del fiore venga visualizzata sopra il suolo reale.

  1. In onSelect, dopo aver aggiunto clone alla scena, aggiungi il codice per riposizionare il piano di 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;
  }
}

Prova

Quando posizioni un girasole, dovresti riuscire a vederlo mentre proietta un'ombra. Se riscontri problemi, controlla il codice final/app.js per vedere un esempio funzionante di questo passaggio.

6. Risorse aggiuntive

Complimenti! Hai raggiunto la fine di questo codelab su AR utilizzando WebXR.

Scopri di più