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.

HTML-Seite erstellen

WebXR erfordert eine Nutzerinteraktion, um eine Sitzung zu starten. Erstellen Sie eine Schaltfläche, die activateXR() aufruft. Nach dem Laden der Seite kann der Nutzer diese Schaltfläche verwenden, um das AR-Erlebnis zu starten.

Erstellen Sie eine neue Datei mit dem Namen index.html und fügen Sie 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>

Third.js initialisieren

Beim Drücken der Starttaste passiert nicht viel. Zum Einrichten einer 3D-Umgebung können Sie eine Rendering-Bibliothek verwenden, um eine Szene darzustellen.

In diesem Beispiel verwenden Sie three.js, eine JavaScript-3D-Renderingbibliothek, die einen WebGL-Renderer bereitstellt. Three.js übernimmt das Rendering, die Kameras und Szenendiagramme, was die Darstellung von 3D-Inhalten im Web vereinfacht.

Szene erstellen

Eine 3D-Umgebung wird im Allgemeinen als Szene modelliert. Erstellen Sie ein THREE.Scene, das AR-Elemente enthält. Mit dem folgenden Code können Sie ein unbeleuchtetes farbiges Feld in AR betrachten.

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

Damit Sie diese Szene im AR-Modus ansehen können, benötigen Sie einen Renderer und eine Kamera. Der Renderer verwendet WebGL, um deine 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 zu WebXR erfolgt über XRSystem.requestSession(). Mit dem Modus „immersive-ar“ lassen sich gerenderte Inhalte in einer realen Umgebung ansehen.

Ein XRReferenceSpace beschreibt das Koordinatensystem, das für Objekte in der virtuellen Welt verwendet wird. Der 'local'-Modus eignet sich am besten für ein AR-Erlebnis mit einem Referenzraum, der einen Ursprung in der Nähe des Zuschauers und stabiles Tracking hat.

Fügen Sie diesen Code am Ende der Funktion activateXR() ein, um XRSession und XRReferenceSpace zu erstellen:

// 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() plant einen Callback, der ausgeführt wird, wenn der Browser einen Frame zeichnen kann.

Rufen Sie während des Callbacks des Animationsframes XRFrame.getViewerPose() auf, um die Position des Betrachters relativ zum lokalen Koordinatenraum zu erhalten. Sie wird verwendet, um die Szenenbildkamera zu aktualisieren. Dabei ändert der Nutzer die virtuelle Welt, 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 Schnittstelle zwischen einem Strahl und einer realen Geometrie ermittelt wird. In Hello WebXR platzieren Sie eine Sonnenblume mithilfe eines Treffertests in der virtuellen Welt.

Demo-Cube entfernen

Entferne den unbeleuchteten Kubus und ersetze ihn durch eine Szene, in der Beleuchtung zu sehen ist:

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

Fordere zum Initialisieren der Treffertestfunktion eine Sitzung mit der Funktion hit-test an. Suche das vorherige requestSession()-Fragment und füge hit-test hinzu:

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

Modellladeprogramm hinzufügen

Derzeit enthält die Szene nur einen farbigen Würfel. Fügen Sie ein Modellladeprogramm hinzu, mit dem GLTF-Modelle geladen werden können.

Fügen Sie im <head>-Tag Ihres Dokuments three.js' GLTFLoader 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 mithilfe des Modellladeprogramms aus dem vorherigen Schritt ein Zielfadenkreuz und eine Sonnenblume aus dem Web.

Fügen Sie diesen Code oberhalb von 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

Zum Berechnen von Kreuzungen mit realen Objekten erstellen Sie mit XRSession.requestHitTestSource() einen XRHitTestSource. Der für die Treffertests verwendete Strahl hat den Referenzraum viewer als Ursprung. Das bedeutet, dass der Treffertest von der Mitte des Darstellungsbereichs aus durchgeführt wird.

Fügen Sie den folgenden Code hinzu, nachdem Sie den Referenzraum local erstellt haben, um eine Treffertestquelle zu erstellen:

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

Angezieltes Fadenkreuz zeichnen

Fügen Sie dem Motiv ein Fadenkreuz hinzu, um zu verdeutlichen, wo die Sonnenblume platziert wird. Dieses Fadenkreuz scheint an realen Oberflächen zu kleben und zeigt an, wo die Sonnenblume verankert sein wird.

XRFrame.getHitTestResults gibt ein Array von XRHitTestResult zurück und zeigt Schnittpunkte mit realer Geometrie an. Verwenden Sie diese Schnittpunkte, um das Zielfadenkreuz in 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 durch Tippen hinzufügen

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

Lassen Sie eine neue Sonnenblume anzeigen, wenn der Nutzer auf den Bildschirm tippt, indem Sie diesen Code während der Initialisierung hinzufügen:

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

Treffertest testen

Verwenden Sie Ihr Mobilgerät, um die Seite aufzurufen. Nachdem WebXR die Umgebung analysiert hat, sollte das Fadenkreuz auf realen Oberflächen erscheinen. Tippe auf das Display, um eine Sonnenblume zu platzieren, die von allen Seiten zu sehen ist.

Nächste Schritte