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 esistenti nel mondo reale.

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

Che cos'è l'AR?

AR è un termine di solito utilizzato per descrivere la fusione tra grafica generata al computer e 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 rimanga 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. Queste operazioni potrebbero includere il rilevamento delle superfici e una stima dell'illuminazione dell'ambiente.

L'AR è diventato ampiamente utilizzato nelle app dopo il rilascio di ARCore di Google e ARKit di Apple, sia per i filtri per i selfie sia per i giochi basati su AR.

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. Utilizza i sensori del dispositivo target per determinarne e monitorarne la posizione e l'orientamento rispetto al mondo reale
  2. Eseguire il rendering di un modello 3D composto sopra la visione in diretta della videocamera
  3. Esegui test sugli hit per posizionare 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 per questo codelab sulla tua workstation:

  1. Apri il file ZIP scaricato. Verrà aperta una cartella principale (ar-with-webxr-master), che contiene le directory di diversi passaggi di questo codelab, insieme a tutte le risorse di cui hai bisogno.

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. che vengono utilizzate come riferimento.

Svolgi tutte le attività di programmazione nella directory work.

Installa server web

  1. Sei libero di utilizzare il tuo server web. Se non ne hai ancora configurato uno, in questa sezione viene spiegato in dettaglio 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. Questo ti consente di pubblicare il lavoro in corso tramite l'URL evidenziato nella finestra di dialogo del server web (nella sezione URL server web).
  2. In Opzioni (richiede riavvio), seleziona la casella di controllo Mostra automaticamente index.html.
  3. Imposta Server web su Arresta, quindi seleziona Avviato.Riavvia Chrome Web Server
  4. Verifica che venga visualizzato almeno uno o più URL del server web: http://127.0.0.1:8887, l'URL localhost predefinito.

Configura port forwarding

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

  1. Sulla workstation di sviluppo, vai a chrome://inspect e fai clic su Port forwarding...: 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 port forwarding:

Configura il port forwarding

Verificare la configurazione

Testa 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 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 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 funzionare con il dispositivo AR.

  1. Fai clic su Avvia realtà aumentata. È possibile che ti venga richiesto di installare ARCore.

Installa prompt 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 poiché più parti del mondo vengono analizzate dalla fotocamera, 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. Nella pagina HTML vengono forniti gli stili CSS e JavaScript per attivare le funzionalità AR di base. Questo accelera il processo di configurazione, consentendo al codelab di concentrarsi sulle funzionalità AR.

La pagina HTML

Crei un'esperienza AR in una pagina web tradizionale utilizzando tecnologie web esistenti. In questa esperienza, viene utilizzato un canvas di rendering a schermo intero, in modo che il file HTML non sia eccessivamente 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 un aspetto simile al seguente. Si tratta di un sottoinsieme dei contenuti effettivi, 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 è app.js. Questo file fornisce un boilerplate per la configurazione di un'esperienza AR.

La 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 l'AR, verifica che esistano navigator.xr e le funzionalità XR necessarie. L'oggetto navigator.xr è il punto di ingresso dell'API WebXR Device, quindi dovrebbe esistere se il dispositivo è compatibile. Verifica inoltre che la modalità di sessione "immersive-ar" sia supportata.

Se non ci sono problemi, facendo clic sul pulsante Entra in realtà aumentata si tenta di creare una sessione XR. In caso contrario, viene chiamato (in shared/utils.js) onNoXRDevice() e viene visualizzato 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();
  }
})();

Richiedi XRSession

Quando fai clic su Attiva realtà aumentata, il codice chiama activateXR(). Verrà 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(). Usa 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");

  // ...
}

Inizializza un XRReferenceSpace

Un simbolo 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");

Definisci un loop di animazione

  1. Usa l'elemento requestAnimationFrame di XRSession per avviare un loop 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, accoda 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(). Questa classe XRViewerPose descrive la posizione e l'orientamento del dispositivo nello spazio. Contiene anche un array di XRView, che descrive ogni punto di osservazione da cui deve essere eseguito il rendering della scena per poter 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 usate per lo più per configurare la matrice di visualizzazione e la matrice di proiezione della videocamera virtuale. Questo influisce sulla disposizione della scena in 3D. Dopo avere configurato 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);
}

Testa

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

In caso di problemi di esecuzione dell'app, consulta le sezioni Introduzione e Configurare l'ambiente di sviluppo.

4. Aggiungere un reticolo di targeting

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

Informazioni su un test di hit

Un test di hit è generalmente un modo per lanciare una linea retta da un punto dello spazio in una direzione e determinare se si interseca con un oggetto di interesse. In questo esempio, il dispositivo viene puntato verso una località del mondo reale. Immagina un raggio che viaggia dalla fotocamera del tuo dispositivo e si avvicini direttamente al mondo fisico di fronte a quest'ultimo.

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.

Messaggio esplicativo hit test

Richiedi un XRSession con funzionalità extra

Per eseguire hit test, sono necessarie funzionalità aggiuntive quando richiedi l'XRSession.

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

Aggiungi un prompt di 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 della località e dell'ambiente.

Usa l'"dom-overlay" del passaggio precedente per visualizzare una richiesta di movimento sopra lo stream della videocamera.

Aggiungi <div> a index.html con ID stabilization. Questo <div> mostra un'animazione agli utenti che rappresenta lo stato di stabilizzazione e chiede loro di spostarsi 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>

Aggiungi un reticolo

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. Compila la nuova scena con un oggetto che rappresenta il punto di collisione. La classe Reticle fornita gestisce il caricamento del modello del 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 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 hit.

  1. Aggiungi il seguente codice 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. Con questo hitTestSource, esegui un test degli hit per ogni frame:
    • Se non ci sono risultati per l'hit test, 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 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.
}

Aggiungi comportamento al tocco sullo 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 è il tocco sullo schermo.

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

In questo esempio, toccando lo schermo viene inserito un girasole in corrispondenza del 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);
  }
}

Testa l'app

Hai creato un reticolo che puoi mirare utilizzando il dispositivo utilizzando gli hit test. Quando tocchi lo schermo, dovresti riuscire a posizionare un girasole nella posizione indicata dal reticolo.

  1. Quando esegui l'app, dovresti essere in grado di vedere un reticolo 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. Potrebbe essere necessario spostarsi per un po' in modo che la piattaforma AR sottostante possa rilevare meglio le superfici nel mondo reale. La scarsa illuminazione e le superfici senza funzionalità riducono la qualità della comprensione della scena e aumentano la possibilità che non venga trovato alcun hit. Se riscontri problemi, controlla il codice step-04/app.js per vedere un esempio funzionante di questo passaggio.

5. Aggiungi ombre

La creazione di una scena realistica comporta elementi come l'illuminazione e le ombre appropriate sugli oggetti digitali che aggiungono realismo e immersività nella scena.

Luci e ombre sono gestite da three.js. Puoi specificare quali luci devono proiettare ombre, quali materiali 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 solo delle ombre.

  1. Attiva le ombre su three.js WebGLRenderer. Dopo aver creato il renderer, imposta i seguenti valori sul 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 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 reale, in modo che l'ombra del fiore venga visualizzata sul terreno reale.

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

Testa

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ù