8.1 Prehľad projektu
Toto je aplikácia WebXR rozšírenej reality pre Meta Quest 3, ktorá kombinuje:
- Passthrough AR — skutočná miestnosť je viditeľná cez kamery na headsete
- Interakcia hit-test — virtuálny kurzor, ktorý sa prichytí na reálne povrchy
- AI detekcia objektov — TensorFlow.js rozpoznáva objekty v kamerovom zázname a zobrazuje popisy v 3D priestore
- Porozumenie scéne — WebXR Plane Detection vizualizuje detekované povrchy (podlaha, steny, stôl)
Živá URL: http://92.113.18.92/
Jeden za druhým:
index.html

8.2 Architektúra projektu
📄 index.html (všetko v jednom)
│
├── HTML → canvas + UI tlačidlo + skrytý video element
├── CSS → priehľadné pozadie, overlay UI
└── JavaScript
├── Three.js → 3D renderovací engine (scéna, kamera, materiály)
├── WebXR API → AR session, hit-test, plane detection
└── TF.js → AI inferencia (coco-ssd model)
Prečo čistá Three.js (bez A-rámu)?
Počas vývoja sa zistilo, že A-Frame má vlastnú internú slučku vykresľovania, ktorá je v konflikte s explicitnou immersive-ar WebXR reláciou. A-Frame začína immersive-vr session (nepriehľadná, bez passthrough) namiesto immersive-ar. Prechod na čistý Three.js nám dal priamu kontrolu nad typom relácie aj nad renderovacím cyklom.
8.3 Technologický stack
|
Technológia |
Verzia |
Úloha |
|
Three.js |
0.157.0 |
3D renderovanie, geometria, materiály |
|
WebXR Device API |
Natívne pre prehliadač |
AR sedenie, test zásahu, detekcia lietadla |
|
TensorFlow.js |
4.15.0 |
Inferenčný engine ML v prehliadači |
|
COCO-SSD |
2.2.3 |
Predtrénovaný model detekcie objektov |
|
getUserMedia API |
Natívne pre prehliadač |
Kamerový prúd na analýzu TF.js |
8.4 Tok aplikácií
Načítanie stránok
→ TF.js model (coco-SSD) sa načítava asynchrónne (~6MB)
→ Skontrolujte: navigator.xr.isSessionSupported('immersive-ar')
→ tlačidlo "Enter AR" sa aktivuje
Používateľ kliká na "Enter AR"
→ Požiadavka: navigator.xr.requestSession('immersive-ar', {...})
→ Quest umožňuje Passthrough (kamera viditeľná cez headset)
→ Súčasne: getUserMedia() → kamerový stream pre TF.js
→ renderer.setAnimationLoop() začína (XR render loop)
Každý snímok (~72fps na Quest 3)
o scene.background = null (zabezpečuje transparentnosť)
o Testovanie zásahov → aktualizuje pozíciu kurzora
o Plane Detection → aktualizuje vizualizáciu povrchu
o Každé 2s → runDetection() → AI inferenciu
o renderer.render(scéna, kamera)
8.5 Podrobné vysvetlenie kódu
1. HTML Štruktúra (riadky 1–78)
Skrytý <video> prvok prijímajúci tok getUserMedia(). TensorFlow.js ho používa ako vstup na inferenciu — nikdy sa nezobrazuje používateľovi, iba analyzuje.

Prekryvná UI vrstva plávajúca nad Three.js plátnom. Ukazovacie udalosti: Žiadne na kontajneri, ale ukazovákové udalosti: všetko len na tlačidle — takže prekryv neblokuje 3D interakcie.
2. Three.js Inicializácia (riadky 84–109)
alpha: true vytvára WebGL plátno s transparentným alfa kanálom — toto je predpoklad pre passthrough. xr.enabled = true aktivuje integrovanú integráciu Three.js WebXR.
Kamera je pridaná do scény. To je dôležité, pretože objekty pripojené ku kamere (podriadené entity) musia byť v hierarchii scény.
Geometria kruhu je otočená o -90° na osi X, takže leží vodorovne na detekovaných povrchoch. Bez tejto rotácie by stál vertikálne.
3. makeLabel() — Textový sprite (riadky 113–138)
TRI. Sprite je objekt, ktorý je vždy otočený ku kamere (billboarding) — ideálny pre označenia v 3D priestore. Kreslí sa na HTML plátne, konvertuje na CanvasTexture a aplikuje sa na SpriteMaterial.
depthTest: false zabezpečuje, že štítok je vždy viditeľný, aj keď je geometricky "za" iným 3D objektom.
4. detectionTo3D() — 2D → 3D projekcia (riadky 140–163)
Toto je matematické jadro integrácie AI-AR.
Príklad: Ak AI deteguje stoličku v ľavej tretine videa, nx ≈ -0,17. To sa premení na záporný uhol (vľavo od osi pohľadu). Štítok je umiestnený 1,8 m pred kamerou týmto smerom.
5. makeBox3D() a bbox2dSize3D() — 3D ohraničujúce boxy (riadky 165–182)
EdgesGeometry + LineSegments vykresľuje iba hrany krabice — efekt tenkého drôteného okraja bez vyplneného povrchu.
Vzorec totalW je štandardná perspektívna projekcia: vo vzdialenosti d závisí viditeľná šírka od zorného poľa. Z toho odvodíme, koľko metrov zodpovedá pixelom ohraničujúcej krabice.
6. runDetection() — AI inferenčný pipeline (riadky 205–247)
cocoModel.detect(tfVideo) prijíma priamo prvok <video> — TF.js interne číta pixelové dáta z aktuálneho video rámca.
Pred.bbox formát: [x, y, šírka, výška] v pixeloch.
Každá detekcia vytvorí pár JS (sprite, box), ktorý vydrží 4 sekundy.
7. WebXR Session — Kľúčové detaily (riadky 274–285)

Prečo immersive-ar a nie immersive-vr?
- Immersive-VR = nepriehľadné čierne pozadie (VR prilba)
- immersive-ar = priechodná kamera + virtuálny obsah prekrytý
Lokálny referenčný priestor na poschodí fixuje súradnicový systém na podlahu miestnosti — Y=0 je na úrovni podlahy.
Hit-test a detekcia roviny sú voliteľné, pretože nie sú podporované na všetkých zariadeniach a verziách prehliadača — deklarovanie ich ako voliteľných zabraňuje zlyhaniu relácie, ak nie sú dostupné
8. Render Loop (riadky 335–395)
Prečo nastaviť AnimationLoop a nepožiadať AnimationFrame?
Renderovací okruh Three.js XR musí byť integrovaný s WebXR rámcovým callbackom. renderer.setAnimationLoop() sa automaticky naviaže na XR reláciu, keď renderer.xr.enabled = true. Alternatíva (manuálne volanie session.requestAnimationFrame()) vyžaduje manuálne volanie renderer.render(), ale riskuje, že chýbajú správne XR matice, ktoré Three.js aplikujú interne.
scene.background = null musí byť volaný v každom snímku , pretože Three.js môže túto hodnotu interne resetovať počas určitých operácií.
9. Detekcia lietadiel (riadky 355–378)
plane.planeSpace je XRSpace, ktorý sleduje fyzický povrch. frame.getPose() vráti svoju pozíciu vo zvolenom referenčnom priestore.
Mapa detekovaných libier (Mapa<XRPlane, TRI. Mesh>) zabraňuje vytváraniu duplicitných sietí pre rovnaký povrch naprieč rámcami.
8.6 Známe obmedzenia
|
Obmedzenia |
Dôvod |
|
AI štítky nie sú pixelovo dokonale zarovnané s objektom |
Quest passthrough kamery a getUserMedia poskytujú rôzne prúdy s rôznym zorným a optickým kalibrovaním |
|
Detekcia roviny vyžaduje dokončenie nastavenia miestnosti s úlohami |
Slúchadlá museli predtým preskenovať miestnosť |
|
getUserMedia môže byť na niektorých zariadeniach zamietnutý |
Závisí to od oprávnení prehliadača |
|
AI inferencia nie je v reálnom čase (beží každé 2 sekundy) |
Coco-SSD je relatívne ťažký model; ľahšie alternatívy (MobileNet SSD) by poskytli vyššiu priepustnosť |
8.7 Zdrojový kód
https://github.com/bciric1/ARVR