Signatur
Beschreibung
XRHitTestResult gehört zum WebXR Hit Test Module. Dieses Modul ergänzt die WebXR Device API. Wenn ein Treffer-Test läuft, der über XRSession.requestHitTestSource() oder requestHitTestSourceForTransientInput() angelegt wurde, liefert jeder XRFrame eine Liste solcher Ergebnisse. Jedes Ergebnis steht für einen Punkt, an dem ein gedachter Strahl eine erkannte reale Oberfläche trifft, etwa einen Boden, einen Tisch oder eine Wand.
Das Interface hat keinen öffentlichen Konstruktor. Man bekommt Instanzen nur über XRFrame.getHitTestResults(hitTestSource), als Array. Bei vorübergehenden Eingaben wie Bildschirmberührungen kommen sie über XRTransientInputHitTestResult.results. Das Array ist nach Entfernung sortiert, der nächstgelegene Treffer steht an erster Stelle.
Die wichtigsten Methoden:
getPose(baseSpace): liefert eineXRPose(Position und Ausrichtung des Treffers) relativ zum angegebenenXRSpace. Die Orientierung zeigt mit der Y-Achse entlang der Oberflächennormalen.createAnchor(): erzeugt einenXRAnchoram Trefferpunkt, sofern das Anchors-Modul unterstützt wird. Das Ergebnis ist einPromise<XRAnchor>.
Typischer Einsatz sind Augmented-Reality-Anwendungen: ein Zielkreuz (Reticle) auf dem Boden anzeigen, virtuelle Möbel auf erkannte Flächen stellen oder Objekte per Tippen platzieren.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $baseSpace Pflicht | XRSpace | Parameter von getPose(): Referenzraum, relativ zu dem die Pose des Treffers berechnet wird, meist der XRReferenceSpace vom Typ 'local' oder 'local-floor'. |
Rückgabewert
getPose(baseSpace) gibt eine XRPose mit transform (Position und Ausrichtung) zurück, oder null, wenn sich die Pose relativ zu baseSpace nicht bestimmen lässt. createAnchor() gibt ein Promise<XRAnchor> zurück.Beispiele
AR-Sitzung mit Treffer-Test starten und Ergebnisse lesen
const startAR = async () => {
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['hit-test', 'local']
});
const viewerSpace = await session.requestReferenceSpace('viewer');
const localSpace = await session.requestReferenceSpace('local');
// Strahl geht von der Blickrichtung des Geräts aus
const hitTestSource = await session.requestHitTestSource({ space: viewerSpace });
const onFrame = (time, frame) => {
session.requestAnimationFrame(onFrame);
const results = frame.getHitTestResults(hitTestSource);
if (results.length > 0) {
const hit = results[0]; // XRHitTestResult, nächster Treffer
const pose = hit.getPose(localSpace);
if (pose) {
const { x, y, z } = pose.transform.position;
console.log(`Treffer bei x=${x.toFixed(2)} y=${y.toFixed(2)} z=${z.toFixed(2)}`);
}
}
};
session.requestAnimationFrame(onFrame);
};
document.querySelector('#ar-button').addEventListener('click', startAR);
Zielkreuz (Reticle) an der Trefferpose ausrichten
// reticle: ein 3D-Objekt (z. B. aus three.js) mit matrix-Eigenschaft
const updateReticle = (frame, hitTestSource, refSpace, reticle) => {
const [hit] = frame.getHitTestResults(hitTestSource);
if (!hit) {
reticle.visible = false;
return;
}
const pose = hit.getPose(refSpace);
reticle.visible = pose !== null;
if (pose) {
// 4x4-Matrix (Float32Array) direkt übernehmen
reticle.matrix.fromArray(pose.transform.matrix);
}
};
Objekt per Tippen verankern mit createAnchor()
const anchors = new Set();
const setupTapToPlace = async (session, refSpace) => {
const transientSource = await session.requestHitTestSourceForTransientInput({
profile: 'generic-touchscreen'
});
let lastHit = null;
const onFrame = (time, frame) => {
session.requestAnimationFrame(onFrame);
const inputResults = frame.getHitTestResultsForTransientInput(transientSource);
for (const input of inputResults) {
if (input.results.length > 0) lastHit = input.results[0];
}
};
session.requestAnimationFrame(onFrame);
session.addEventListener('select', async () => {
if (!lastHit?.createAnchor) return; // Anchors-Modul nicht verfügbar
try {
const anchor = await lastHit.createAnchor();
anchors.add(anchor);
console.log('Anker erstellt, Anzahl:', anchors.size);
} catch (err) {
console.error('Anker fehlgeschlagen:', err);
}
});
};
// Wichtig · Fallstricke
- Kompatibilität: Treffer-Tests und AR-Sitzungen werden praktisch nur von Chromium-Browsern unterstützt, vor allem Chrome für Android mit ARCore. Firefox und Safari auf dem Desktop kennen die Schnittstelle nicht. Vor der Nutzung mit
navigator.xr?.isSessionSupported('immersive-ar')prüfen. - Sicherer Kontext: WebXR funktioniert nur über HTTPS (oder
localhost). Eine immersive Sitzung braucht eine Benutzeraktion, zum Beispiel einen Klick. - Feature anfordern:
'hit-test'muss inrequiredFeaturesoderoptionalFeaturesvonrequestSession()stehen. Sonst schlägtrequestHitTestSource()fehl. - Nur im aktuellen Frame gültig: Ein
XRHitTestResultgehört zu demXRFrame, in dem es entstanden ist.getPose()außerhalb des Frame-Callbacks löst einenInvalidStateErroraus. Deshalb die Pose-Daten kopieren, nicht das Ergebnisobjekt aufheben. Eine Ausnahme istcreateAnchor(), das man im zugehörigenselect-Ereignis aufrufen kann, wenn der Treffer frisch ist. - Leere Ergebnisse: Solange das Gerät noch keine Flächen erkannt hat, ist das Array leer.
getPose()kann außerdemnullliefern. Beide Fälle immer abfangen. - Ressourcen freigeben: Nicht mehr benötigte Quellen mit
hitTestSource.cancel()beenden. Das spart Rechenleistung und Akku. createAnchor()gibt es nur, wenn das WebXR Anchors Module unterstützt und das Feature'anchors'angefordert wurde.