Crea una sessione AR immersiva con WebXR

Questa pagina ti guiderà nella creazione di una semplice applicazione AR immersiva utilizzando WebXR.

Per iniziare, devi avere un ambiente di sviluppo compatibile con WebXR.

Crea una pagina HTML

WebXR richiede l'interazione dell'utente per poter avviare una sessione. Crea un pulsante che chiami activateXR(). Dopo aver caricato la pagina, l'utente può utilizzare questo pulsante per avviare l'esperienza AR.

Crea un nuovo file denominato index.html e aggiungici il seguente codice HTML:

<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <title>Hello WebXR!</title>

  <!-- three.js -->
  <script src="https://unpkg.com/three@0.126.0/build/three.js"></script>
</head>
<body>

<!-- Starting an immersive WebXR session requires user interaction.
    We start this one with a simple button. -->
<button onclick="activateXR()">Start Hello WebXR</button>
<script>
async function activateXR() {
  // Add a canvas element and initialize a WebGL context that is compatible with WebXR.
  const canvas = document.createElement("canvas");
  document.body.appendChild(canvas);
  const gl = canvas.getContext("webgl", {xrCompatible: true});

  // To be continued in upcoming steps.
}
</script>
</body>
</html>

Inizializzare tre.js

Non succede molto quando premi il pulsante Start. Per configurare un ambiente 3D, puoi utilizzare una libreria di rendering per visualizzare una scena.

In questo esempio utilizzerai three.js, una libreria di rendering 3D JavaScript che fornisce un renderer WebGL. Three.js gestisce il rendering, le fotocamere e i grafici delle scene, semplificando la visualizzazione di contenuti 3D sul web.

Creare una scena

In genere, un ambiente 3D è modellato come una scena. Crea una THREE.Scene contenente elementi AR. Il codice che segue ti consente di guardare un riquadro colorato non illuminato in AR.

Aggiungi questo codice in fondo alla funzione activateXR():

const scene = new THREE.Scene();

// The cube will have a different color on each side.
const materials = [
  new THREE.MeshBasicMaterial({color: 0xff0000}),
  new THREE.MeshBasicMaterial({color: 0x0000ff}),
  new THREE.MeshBasicMaterial({color: 0x00ff00}),
  new THREE.MeshBasicMaterial({color: 0xff00ff}),
  new THREE.MeshBasicMaterial({color: 0x00ffff}),
  new THREE.MeshBasicMaterial({color: 0xffff00})
];

// Create the cube and add it to the demo scene.
const cube = new THREE.Mesh(new THREE.BoxBufferGeometry(0.2, 0.2, 0.2), materials);
cube.position.set(1, 1, 1);
scene.add(cube);

Impostazione del rendering utilizzando tre.js

Per poter visualizzare questa scena in AR, sono necessari un renderer e una fotocamera. Il renderer utilizza WebGL per disegnare la scena sullo schermo. La fotocamera descrive l'area visibile da cui viene visualizzata la scena.

Aggiungi questo codice in fondo alla funzione activateXR():

// Set up the WebGLRenderer, which handles rendering to the session's base layer.
const renderer = new THREE.WebGLRenderer({
  alpha: true,
  preserveDrawingBuffer: true,
  canvas: canvas,
  context: gl
});
renderer.autoClear = false;

// The API directly updates the camera matrices.
// Disable matrix auto updates so three.js doesn't attempt
// to handle the matrices independently.
const camera = new THREE.PerspectiveCamera();
camera.matrixAutoUpdate = false;

Crea una sessione XR

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

XRReferenceSpace descrive il sistema di coordinate utilizzato per gli oggetti nel mondo virtuale. La modalità 'local' è la più adatta per un'esperienza AR, con uno spazio di riferimento che ha un'origine vicino al visualizzatore e un tracciamento stabile.

Per creare un XRSession e un XRReferenceSpace, aggiungi questo codice in fondo alla funzione activateXR():

// Initialize a WebXR session using "immersive-ar".
const session = await navigator.xr.requestSession("immersive-ar");
session.updateRenderState({
  baseLayer: new XRWebGLLayer(session, gl)
});

// A 'local' reference space has a native origin that is located
// near the viewer's position at the time the session was created.
const referenceSpace = await session.requestReferenceSpace('local');

Esegui il rendering della scena

Ora puoi eseguire il rendering della scena. XRSession.requestAnimationFrame() pianifica un callback che viene eseguito quando il browser è pronto a disegnare un frame.

Durante il callback del frame dell'animazione, chiama XRFrame.getViewerPose() per ottenere la posa del visualizzatore in relazione allo spazio delle coordinate locali. Viene utilizzato per aggiornare la videocamera della scena, modificando il modo in cui l'utente vede il mondo virtuale prima che il renderer disegna la scena utilizzando la videocamera aggiornata.

Aggiungi questo codice in fondo alla funzione activateXR():

// Create a render loop that allows us to draw on the AR view.
const onXRFrame = (time, frame) => {
  // Queue up the next draw request.
  session.requestAnimationFrame(onXRFrame);

  // Bind the graphics framebuffer to the baseLayer's framebuffer
  gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer)

  // Retrieve the pose of the device.
  // XRFrame.getViewerPose can return null while the session attempts to establish tracking.
  const pose = frame.getViewerPose(referenceSpace);
  if (pose) {
    // In mobile AR, we only have one view.
    const view = pose.views[0];

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

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

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

Esegui Hello WebXR

Vai al file WebXR sul tuo dispositivo. Dovresti riuscire a visualizzare un cubo colorato da tutti i lati.

Aggiungere un hit test

Un modo comune di interagire con il mondo AR è tramite un hit test, che trova un'intersezione tra un raggio e la geometria del mondo reale. In Hello WebXR, utilizzerai un test di successo per posizionare un girasole nel mondo virtuale.

Rimuovi il cubo della demo

Rimuovi il cubo non illuminato e sostituiscilo con una scena che includa l'illuminazione:

const scene = new THREE.Scene();

const directionalLight = new THREE.DirectionalLight(0xffffff, 0.3);
directionalLight.position.set(10, 15, 10);
scene.add(directionalLight);

Usa la funzionalità hit-test

Per inizializzare la funzionalità di hit test, richiedi una sessione con la funzionalità hit-test. Trova il frammento requestSession() precedente e aggiungi hit-test:

const session = await navigator.xr.requestSession("immersive-ar", {requiredFeatures: ['hit-test']});

Aggiungi un caricatore di modelli

Attualmente, la scena contiene solo un cubo colorato. Per rendere l'esperienza più interessante, aggiungi un caricatore di modelli, che consente di caricare i modelli GLTF.

Nel tag <head> del documento, aggiungi Three.js' GLTFLoader.

<!-- three.js -->
<script src="https://unpkg.com/three@0.126.0/build/three.js"></script>

<script src="https://unpkg.com/three@0.126.0/examples/js/loaders/GLTFLoader.js"></script>

Carica modelli GLTF

Utilizza il caricatore di modelli del passaggio precedente per caricare un reticolo di targeting e un girasole dal Web.

Aggiungi questo codice sopra onXRFrame:

const loader = new THREE.GLTFLoader();
let reticle;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", function(gltf) {
  reticle = gltf.scene;
  reticle.visible = false;
  scene.add(reticle);
})

let flower;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/sunflower/sunflower.gltf", function(gltf) {
  flower = gltf.scene;
});

// Create a render loop that allows us to draw on the AR view.
const onXRFrame = (time, frame) => {

Creare una sorgente di hit test

Per calcolare le intersezioni con oggetti reali, crea un XRHitTestSource utilizzando XRSession.requestHitTestSource(). Il raggio utilizzato per gli hit test ha come origine lo spazio di riferimento viewer, il che significa che l'hit test viene eseguito dal centro dell'area visibile.

Per creare una sorgente di hit test, aggiungi questo codice dopo aver creato lo spazio di riferimento local:

// A 'local' reference space has a native origin that is located
// near the viewer's position at the time the session was created.
const referenceSpace = await session.requestReferenceSpace('local');

// Create another XRReferenceSpace that has the viewer as the origin.
const viewerSpace = await session.requestReferenceSpace('viewer');
// Perform hit testing using the viewer as origin.
const hitTestSource = await session.requestHitTestSource({ space: viewerSpace });

Disegno di un reticolo di targeting

Per chiarire dove verrà posizionato il girasole, aggiungi alla scena un reticolo mirato. Questo reticolo sembrerà attaccato a superfici reali, a indicare dove sarà ancorato il girasole.

XRFrame.getHitTestResults restituisce un array di XRHitTestResult e espone le intersezioni con la geometria del mondo reale. Utilizza queste intersezioni per posizionare il reticolo di targeting su ogni frame.

camera.projectionMatrix.fromArray(view.projectionMatrix);
camera.updateMatrixWorld(true);

const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0 && reticle) {
  const hitPose = hitTestResults[0].getPose(referenceSpace);
  reticle.visible = true;
  reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z)
  reticle.updateMatrixWorld(true);
}

Aggiunta di interazioni a tocco

XRSession riceve eventi select quando l'utente completa un'azione principale. In una sessione AR, corrisponde a un tocco sullo schermo.

Mostra un nuovo girasole quando l'utente tocca lo schermo aggiungendo questo codice durante l'inizializzazione:

let flower;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/sunflower/sunflower.gltf", function(gltf) {
  flower = gltf.scene;
});

session.addEventListener("select", (event) => {
  if (flower) {
    const clone = flower.clone();
    clone.position.copy(reticle.position);
    scene.add(clone);
  }
});

Testare gli hit test

Accedi alla pagina dal tuo dispositivo mobile. Una volta che WebXR avrà compreso l'ambiente, il reticolo dovrebbe apparire sulle superfici del mondo reale. Tocca lo schermo per posizionare un girasole, che può essere visto da tutti i lati.

Passaggi successivi