Signatur
Beschreibung
Die schreibgeschützte Eigenschaft results der Schnittstelle XRTransientInputHitTestResult liefert ein Array von XRHitTestResult-Objekten. Jedes Objekt beschreibt einen Schnittpunkt zwischen dem Zielstrahl einer transienten Eingabequelle und einer realen Fläche oder einem erkannten Objekt, etwa wenn man in einer AR-Sitzung mit dem Finger auf den Bildschirm tippt.
Man erhält solche Ergebnisse, indem man zuerst mit XRSession.requestHitTestSourceForTransientInput() eine XRTransientInputHitTestSource anfordert und dann in jedem Frame XRFrame.getHitTestResultsForTransientInput(source) aufruft. Das liefert pro aktiver Eingabequelle ein XRTransientInputHitTestResult. Dessen Eigenschaft inputSource gibt an, zu welcher Eingabe die Treffer gehören, und results enthält die eigentlichen Treffer.
Die Treffer sind nach Entfernung sortiert, der nächstgelegene steht also an Index 0. Mit XRHitTestResult.getPose(referenceSpace) berechnet man die Position und Ausrichtung eines Treffers, um dort zum Beispiel virtuelle Objekte zu platzieren. Mit createAnchor() kann man ihn außerdem dauerhaft als Anker verankern.
Rückgabewert
XRHitTestResult-Objekten, nach Entfernung sortiert (nächster Treffer zuerst). Ist leer, wenn der Strahl keine reale Geometrie trifft.Beispiele
Hit-Test-Quelle für Bildschirm-Tipps anfordern
// Setzt eine AR-Sitzung mit Feature 'hit-test' voraus
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['hit-test']
});
const refSpace = await session.requestReferenceSpace('local');
// Profil 'generic-touchscreen' = Tippen auf dem Smartphone-Display
const transientSource = await session.requestHitTestSourceForTransientInput({
profile: 'generic-touchscreen',
offsetRay: new XRRay()
});
console.log('Hit-Test-Quelle bereit:', transientSource);
Nächsten Treffer pro Frame auswerten
const onXRFrame = (time, frame) => {
const session = frame.session;
session.requestAnimationFrame(onXRFrame);
const hitResults = frame.getHitTestResultsForTransientInput(transientSource);
for (const inputResult of hitResults) {
// results ist nach Entfernung sortiert
const [nearest] = inputResult.results;
if (!nearest) continue;
const pose = nearest.getPose(refSpace);
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(onXRFrame);
Objekt beim Tippen platzieren (select-Event)
let lastHits = [];
const onXRFrame = (time, frame) => {
frame.session.requestAnimationFrame(onXRFrame);
lastHits = frame.getHitTestResultsForTransientInput(transientSource);
};
session.addEventListener('select', (event) => {
const match = lastHits.find((r) => r.inputSource === event.inputSource);
if (match && match.results.length > 0) {
const pose = match.results[0].getPose(refSpace);
placeModelAt(pose.transform); // eigene Funktion, z. B. mit three.js
console.log('Modell platziert, Treffer insgesamt:', match.results.length);
}
});
session.requestAnimationFrame(onXRFrame);
// Wichtig · Fallstricke
- Browser-Unterstützung: Nur in Chromium-basierten Browsern mit AR-Unterstützung (Chrome für Android mit ARCore, Meta Quest Browser). Firefox und Safari unterstützen das WebXR Hit Test Module nicht. Vorher mit
navigator.xr?.isSessionSupported('immersive-ar')prüfen. - Sicherer Kontext: WebXR funktioniert nur über HTTPS. Die Sitzung muss durch eine Nutzeraktion gestartet werden, und das Feature
'hit-test'muss inrequiredFeaturesoderoptionalFeaturesangegeben sein. - Kurzlebige Ergebnisse:
XRHitTestResult-Objekte gelten nur für den Frame, in dem sie entstanden sind.getPose()außerhalb dieses Frames wirft eineInvalidStateError-Ausnahme. Für dauerhafte Positionen die Pose kopieren oder mitcreateAnchor()einen Anker erzeugen. - Leeres Array:
resultskann leer sein, zum Beispiel solange die Umgebung noch nicht erfasst ist. Deshalb immer die Länge prüfen, bevor man aufresults[0]zugreift. - Das Array ist eingefroren. Methoden wie
push()odersort()ändern es nicht, sondern werfen im strikten Modus einenTypeError. - Die Hit-Test-Quelle nach Gebrauch mit
transientSource.cancel()freigeben, damit keine unnötige Rechenarbeit anfällt.