Mit WebXR immersive AR-Sitzungen erstellen

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

Sie benötigen dazu eine WebXR-kompatible Entwicklungsumgebung.

HTML-Seite erstellen

Damit WebXR eine Sitzung starten kann, ist eine Nutzerinteraktion erforderlich. Erstelle eine Schaltfläche zum Aufrufen von activateXR(). 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 ein nicht beleuchtetes Feld in AR 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, von dem aus 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(). Mit dem Modus „immersive-ar“ können gerenderte Inhalte in einer realen Umgebung angesehen werden.

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 Callbacks für den Animationsframe XRFrame.getViewerPose() auf, um die Position des Betrachters in Bezug auf den lokalen Koordinatenraum zu ermitteln. Damit wird die Kamera in der Szene aktualisiert und die Ansicht der virtuellen Welt geä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 für die Interaktion mit der AR-Welt ist ein Treffertest, bei dem eine Schnittstelle zwischen einem Strahl und realer Geometrie 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);

Funktion „hit-test“ verwenden

Wenn du die Funktion für Treffertests initialisieren möchtest, musst du eine Sitzung mit der Funktion hit-test anfordern. 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

Im Moment 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 Treffertests verwendete Strahl hat den Referenzraum viewer als Ursprung. Dies bedeutet, dass der Treffertest von der Mitte des Darstellungsbereichs 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 Fadenkreuz 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. Verwenden Sie diese Schnittpunkte, um das Targeting-Retikal auf jedem Frame zu 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 empfängt 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

Rufen Sie die Seite mit Ihrem 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 zu sehen ist.

Nächste Schritte