Start · Sprachen · JavaScript · Referenz · XRHitTestResult.createAnchor()

XRHitTestResult.createAnchor()

Methode

Erstellt aus einem Hit-Test-Treffer asynchron einen <code>XRAnchor</code>, der an der getroffenen realen Oberfläche verankert bleibt und vom System fortlaufend nachgeführt wird.

seit JavaScript Experimentell: Chrome/Edge 85+ (Android, ARCore), Kategorie: webapi

Signatur

XRHitTestResult.prototype.createAnchor()

Beschreibung

Die Methode createAnchor() gehört zum WebXR Anchors Module und erweitert die Schnittstelle XRHitTestResult. Sie erzeugt aus einem Treffer eines Hit-Tests, also dem Schnittpunkt eines Strahls mit einer erkannten realen Fläche wie Boden, Tisch oder Wand, einen Anker (XRAnchor). Das Gerät führt einen Anker fortlaufend nach. Er bleibt deshalb auch dann an derselben Stelle der realen Welt, wenn das System sein Bild der Umgebung nachträglich korrigiert, etwa weil eine Fläche genauer erkannt wurde.

Gegenüber XRFrame.createAnchor(pose, space) hat die Hit-Test-Variante einen Vorteil: Der Anker wird direkt an das getroffene reale Objekt gebunden. Wenn das System die Lage dieser Fläche anpasst, wandert der Anker mit. Typisch ist das in AR-Anwendungen, in denen Nutzer virtuelle Objekte wie Möbel, Markierungen oder Notizen auf echten Flächen ablegen und die Objekte dort stabil bleiben sollen.

Die Methode funktioniert nur in einer immersive-ar-Sitzung, bei der die Features "hit-test" und "anchors" angefordert wurden. Sie gibt ein Promise zurück. Der fertige Anker ist ab dem nächsten Frame in XRFrame.trackedAnchors enthalten. Seine aktuelle Lage fragt man in jedem Frame mit frame.getPose(anchor.anchorSpace, referenceSpace) ab.

Rückgabewert

Typ
Promise<XRAnchor>
Beschreibung
Ein Promise, das mit dem neu erzeugten XRAnchor erfüllt wird. Es wird abgelehnt, zum Beispiel mit NotSupportedError, wenn das Feature "anchors" nicht aktiviert ist, mit InvalidStateError, wenn die Sitzung beendet oder der Frame nicht mehr aktiv ist, oder mit OperationError, wenn das System den Anker nicht anlegen konnte.

Beispiele

AR-Sitzung mit Hit-Test und Ankern starten

const startAR = async () => {
  if (!(await navigator.xr?.isSessionSupported('immersive-ar'))) {
    console.log('immersive-ar wird nicht unterstützt');
    return;
  }
  const session = await navigator.xr.requestSession('immersive-ar', {
    requiredFeatures: ['hit-test', 'anchors'],
    optionalFeatures: ['dom-overlay'],
    domOverlay: { root: document.body }
  });

  const refSpace = await session.requestReferenceSpace('local');
  const viewerSpace = await session.requestReferenceSpace('viewer');
  // Strahl aus der Bildschirmmitte in Blickrichtung
  const hitTestSource = await session.requestHitTestSource({ space: viewerSpace });

  return { session, refSpace, hitTestSource };
};

// Muss durch eine Nutzeraktion ausgelöst werden
document.querySelector('#ar-button').addEventListener('click', startAR);

Beim Tippen einen Anker am Hit-Test-Treffer anlegen

const anchors = new Set();
let latestHit = null;

const onXRFrame = (time, frame) => {
  const session = frame.session;
  session.requestAnimationFrame(onXRFrame);

  const hits = frame.getHitTestResults(hitTestSource);
  latestHit = hits.length > 0 ? hits[0] : null;
};

session.addEventListener('select', async () => {
  if (!latestHit) return;
  try {
    const anchor = await latestHit.createAnchor();
    anchors.add(anchor);
    console.log('Anker erstellt, Anzahl:', anchors.size);
  } catch (err) {
    console.error('Anker konnte nicht erstellt werden:', err.name);
  }
});

session.requestAnimationFrame(onXRFrame);
Anker erstellt, Anzahl: 1

Verankerte Objekte in jedem Frame positionieren und wieder löschen

const drawAnchoredObjects = (frame, refSpace) => {
  for (const anchor of anchors) {
    // Wird der Anker nicht mehr verfolgt, fehlt er in trackedAnchors
    if (!frame.trackedAnchors.has(anchor)) {
      anchors.delete(anchor);
      continue;
    }
    const pose = frame.getPose(anchor.anchorSpace, refSpace);
    if (pose) {
      // pose.transform.matrix ist eine Float32Array(16) für den Renderer
      renderModelAt(pose.transform.matrix);
    }
  }
};

// Alle Anker entfernen, z. B. über einen "Zurücksetzen"-Button
const clearAnchors = () => {
  for (const anchor of anchors) anchor.delete();
  anchors.clear();
};

// Wichtig · Fallstricke

  • Experimentelle API: Die Methode läuft derzeit praktisch nur in Chromium-Browsern auf Android mit ARCore, zum Beispiel Chrome ab Version 85. Firefox und Safari unterstützen sie nicht, auf Desktop-Rechnern gibt es in der Regel kein immersive-ar. Vor der Nutzung sollte man die Unterstützung prüfen: mit isSessionSupported('immersive-ar') und mit 'createAnchor' in XRHitTestResult.prototype.
  • Feature anfordern: Ohne "anchors" in requiredFeatures oder optionalFeatures wird das Promise abgelehnt. Ein Feature unter optionalFeatures kann der Browser verweigern. Deshalb sollte man die Ablehnung immer mit try/catch abfangen.
  • Nur im aktiven Frame gültig: Ein XRHitTestResult gilt nur für den Frame, in dem es entstanden ist. Einen Anker aus einem veralteten Ergebnis zu erzeugen, kann scheitern. Deshalb am besten zeitnah zum Frame aufrufen, etwa im select-Ereignis mit dem Treffer aus dem letzten Frame.
  • Asynchron: Der Anker ist nicht sofort in frame.trackedAnchors enthalten. Außerdem kann das Tracking jederzeit abreißen. In diesem Fall fehlt der Anker in trackedAnchors, oder getPose() liefert null.
  • Ressourcen: Anker kosten Rechenleistung beim Tracking. Nicht mehr benötigte Anker sollte man mit XRAnchor.delete() freigeben. Beim Ende der Sitzung werden alle Anker automatisch ungültig.
  • Sicherheit und Datenschutz: Die API funktioniert nur in einem sicheren Kontext (HTTPS). Die Sitzung braucht eine Nutzeraktion und gegebenenfalls eine Berechtigung, weil Anker Rückschlüsse auf die reale Umgebung erlauben.