Mit WebXR immersive AR-Sitzungen erstellen

Auf dieser Seite erfahren Sie, wie Sie mit WebXR eine einfache immersive AR-Anwendung erstellen.

Sie benötigen eine WebXR-kompatible Entwicklungsumgebung, um loszulegen.

HTML-Seite erstellen

Für WebXR ist eine Nutzerinteraktion erforderlich, um eine Sitzung starten zu können. Erstellen Sie eine Schaltfläche, die activateXR() aufruft. Nach dem Laden der Seite kann der Nutzer über diese Schaltfläche die AR-Funktion starten.

Erstellen Sie eine neue Datei mit dem Namen index.html und fügen Sie ihr den folgenden HTML-Code hinzu:

<!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>

three.js initialisieren

Wenn Sie auf die Schaltfläche „Starten“ klicken, passiert nicht viel. Um eine 3D-Umgebung einzurichten, können Sie eine Rendering-Bibliothek verwenden, um eine Szene anzuzeigen.

In diesem Beispiel verwenden Sie three.js, eine JavaScript-3D-Rendering-Bibliothek mit einem WebGL-Renderer. Three.js verarbeitet Rendering, Kameras und Szenengraphen, wodurch die Darstellung von 3D-Inhalten im Web einfacher wird.

Szene erstellen

Eine 3D-Umgebung wird in der Regel als Szene modelliert. Erstellen Sie eine THREE.Scene mit AR-Elementen. Mit dem folgenden Code können Sie sich in AR einen nicht beleuchteten farbigen Quader ansehen.

Fügen Sie diesen Code am Ende der Funktion activateXR() ein:

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

Rendering mit three.js einrichten

Um diese Szene in AR ansehen zu können, benötigen Sie einen Renderer und eine Kamera. Der Renderer verwendet WebGL, um die Szene auf dem Bildschirm zu zeichnen. Die Kamera beschreibt den Darstellungsbereich, aus dem die Szene betrachtet wird.

Fügen Sie diesen Code am Ende der Funktion activateXR() ein:

// 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;

XRSession erstellen

Der Einstiegspunkt für WebXR ist XRSystem.requestSession(). Verwenden Sie den Modus immersive-ar, um gerenderte Inhalte in einer realen Umgebung anzusehen.

Ein XRReferenceSpace beschreibt das Koordinatensystem, das für Objekte in der virtuellen Welt verwendet wird. Der Modus 'local' eignet sich am besten für AR-Inhalte mit einem Referenzraum, dessen Ursprung sich in der Nähe des Betrachters befindet, und stabiler Verfolgung.

Wenn Sie XRSession und XRReferenceSpace erstellen möchten, fügen Sie diesen Code unten in die activateXR()-Funktion ein:

// 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');

Szene rendern

Jetzt können Sie die Szene rendern. XRSession.requestAnimationFrame() löst einen Callback aus, der ausgeführt wird, wenn der Browser einen Frame zeichnen kann.

Rufen Sie während des Rückrufs für den Animationsframe XRFrame.getViewerPose() auf, um die Haltung des Betrachters relativ zum lokalen Koordinatenraum abzurufen. Damit wird die Kamera in der Szene aktualisiert und die Ansicht der virtuellen Welt verändert, bevor der Renderer die Szene mit der aktualisierten Kamera zeichnet.

Fügen Sie diesen Code am Ende der Funktion activateXR() ein:

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

Hello WebXR ausführen

Rufen Sie die WebXR-Datei auf Ihrem Gerät auf. Sie sollten einen farbigen Würfel von allen Seiten sehen können.

Treffertest hinzufügen

Eine gängige Methode zur Interaktion mit der AR-Welt ist ein Treffertest, bei dem eine Schnittmenge zwischen einem Strahl und der Geometrie der realen Welt gefunden wird. In Hello WebXR platzieren Sie mithilfe eines Treffertests eine Sonnenblume in der virtuellen Welt.

Demowürfel entfernen

Entfernen Sie den nicht beleuchteten Würfel und ersetzen Sie ihn durch eine Szene mit Beleuchtung:

const scene = new THREE.Scene();

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

hit-test-Funktion verwenden

Wenn Sie die Funktion für Treffertests initialisieren möchten, fordern Sie eine Sitzung mit der Funktion hit-test an. Suchen Sie das vorherige requestSession()-Fragment und fügen Sie ihm hit-test hinzu:

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

Modell-Ladeprogramm hinzufügen

Derzeit enthält die Szene nur einen farbigen Würfel. Um die App interessanter zu gestalten, fügen Sie einen Modell-Lademechanismus hinzu, mit dem GLTF-Modelle geladen werden können.

Fügen Sie dem <head>-Tag Ihres Dokuments GLTFLoader von three.js hinzu.

<!-- 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>

GLTF-Modelle laden

Laden Sie mit dem Modell-Ladeprogramm aus dem vorherigen Schritt ein Zielkreuz und eine Sonnenblume aus dem Web.

Fügen Sie diesen Code über onXRFrame ein:

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) => {

Treffertestquelle erstellen

Wenn Sie Überschneidungen mit realen Objekten berechnen möchten, erstellen Sie eine XRHitTestSource mit XRSession.requestHitTestSource(). Der für den Kollisionstest verwendete Strahl hat den viewer-Referenzraum als Ursprung. Das bedeutet, dass der Kollisionstest von der Mitte des Ansichtsbereichs aus durchgeführt wird.

Wenn Sie eine Treffertestquelle erstellen möchten, fügen Sie diesen Code nach dem Erstellen des local-Referenzbereichs hinzu:

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

Targeting-Fadenkreuz zeichnen

Fügen Sie der Szene ein Zielkreuz hinzu, damit klar ist, wo die Sonnenblume platziert wird. Dieses Fadenkreuz scheint an realen Oberflächen zu haften und gibt an, wo die Sonnenblume verankert wird.

XRFrame.getHitTestResults gibt ein Array von XRHitTestResult zurück und zeigt Überschneidungen mit realer Geometrie an. Mithilfe dieser Überschneidungen können Sie das Targeting-Fadenkreuz in jedem Frame positionieren.

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

Interaktionen per Tippen hinzufügen

XRSession erhält select-Ereignisse, wenn der Nutzer eine primäre Aktion ausführt. In einer AR-Sitzung entspricht dies einem Tippen auf den Bildschirm.

Wenn der Nutzer auf das Display tippt, soll eine neue Sonnenblume angezeigt werden. Fügen Sie dazu während der Initialisierung diesen Code hinzu:

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

Trefferprüfung testen

Rufe die Seite auf deinem Mobilgerät auf. Nachdem WebXR sich ein Bild von der Umgebung gemacht hat, sollte das Fadenkreuz auf realen Oberflächen erscheinen. Tippen Sie auf den Bildschirm, um eine Sonnenblume zu platzieren, die von allen Seiten sichtbar ist.

Nächste Schritte