This shows you the differences between two versions of the page.
irva:laboratoare:06 [2022/11/22 12:55] andrei.lapusteanu |
irva:laboratoare:06 [2023/12/12 01:15] (current) andrei.lapusteanu typo |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 06. ManoMotion. Hand tracking & gesture detection in AR ===== | + | ===== Laboratorul 06. Google Cardboard ===== |
- | <note important>**Repo-ul a fost actualizat!** Pull the changes (sau descărcați-l de [[https://github.com/Maria-Anca-Balutoiu/IRVA|aici]])</note> | + | <note important>Pentru laboratoarele de VR va trebui să descărcați acest repo: https://github.com/Andrei-Lapusteanu/IRVA_VR. **We strongly recommend** să vă clonați repo-ul (nu download .zip) întrucât vor exsita update-uri la acesta!</note> |
- | <note important>For some weird reason, prima oară când faceți build la scena laboratorului pe telefon (instalati .APK-ul), instanțierea din etapa 2 nu are loc corect. **Închideți si deschideți din nou aplicația.**</note> | + | ==== Introducere ==== |
- | ManoMotion este un SDK ce permite dezvoltarea de aplicații în AR, unde **modalitatea de input este determinată de hand tracking**. | + | **Google Cardboard (XR Plugin for Unity)** este un SDK ce permite dezvoltatorilor să creeze experințe în realitate virtuală folosind dispozitive mobile (smartphone-uri) în motorul de jocuri Unty. Acest plugin este destinat utilizării împreună cu Google Cardboard (vezi imaginea de mai jos), un dispozitiv de tip holder pentru telefoane, ce permite o variantă low-cost de a experimenta cu realitatea virtuală. |
- | SDK-ul este construit pe baza unor metode de computer vision și machine learning ce facilitează **detecția mâinilor** – este antrenat, de asemenea, să recunoască o serie de **gesturi**, de care vom vorbi în acest laborator. | + | {{ :irva:laboratoare:l6_cardboardgif.gif?400 |}} |
- | Putem crea aplicații sau jocuri folosinf ARFoundation + ManoMotion care să nu necesite interacțiunea cu touchscreen-ul – modalitatea de input fiind dictată de către poziția mâinii detectate, precum și a gesturilor efectuate. | + | Aceste dispozitive de tip holder se pot achiziționa de la diverse brand-uri – se pot achiziționa, de asemenea, controller-e de tip joystick ce comunică pe Bluetooth cu telefonul, pentru a avea un control sporit în scenele virtuale (de exemplu, se poate implementa movement-ul sau diferite interacțiuni folosing aceste controller-e). |
- | <note tip>Versiunea de SDK implementată în framework-ul de laborator utilizează ARFoundation (sorry, no editor play sau instant preview!). Ne vom folosi de algoritmii de plane detection oferiți de către ARFoundation – similar implementărilor din laboratoarele precedente.</note> | + | {{ :irva:laboratoare:l6_bt_controller.jpg?200 |}} |
- | ==== Working Demo ==== | + | În continuare puteți studia un demo ce prezintă laboratorul cu task-urile rezolvate (fără bonus-uri): |
- | Un preview asupra aplicației la care veți lucra în acest laborator îl puteți viziona în următorul videoclip – versiunea prezentată este cea finală (cu task-urile rezolvate). | + | <video here, eventually> |
- | <html> | + | === Higlights tehnologie === |
- | <p style="text-align:center;margin:auto;"> | + | |
- | <iframe width="560" height="315" src="https://www.youtube.com/embed/35mzT9UAPd0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> | + | |
- | </p> | + | |
- | </html> | + | |
- | ==== Setup ManoMotion în Unity ==== | + | * **Compatibilitate**: Există suport atât pentru Android cât și pentru iOS |
+ | * **Integrare seamless**: Se folosește de framework-ul de XR din Unity, facilitând astfel dezvoltarea rapidă a aplicațiilor de tip VR | ||
+ | * **Feature-uri**: Suport pentru head tracking (folosind senzorii giroscopici și accelerometrele găsite în telefoane), randare stereoscopică (un render pentru fiecare ochi – se desenează fiecare render pe jumătate din ecranul dispozitivului), precum și diverse metode implementate în software, precum gaze interaction, ce permite interacțiunea cu diverse obicte prin simpla privire a acestora | ||
- | ManoMotion SDK (împreună cu ARFoundation) sunt deja incluse în laborator, iar setările aferente build-ului au fost realizate (s-ar putea sa trebuiască să schimbați doar target platform-ul). | + | <note tip>În mod evident, soluțiile dedicate pentru VR (HTC Vive, Meta Quest 2/3, Meta Pro, etc.) oferă o experiență virtuală mult superioară procesării posibile pe un smartphone, dar acest plugin ne permite să avem un “taste” al tehnologiei VR într-un mod accesibil.</note> |
- | De asemenea, în scena aferentă laboratorului acesta (L6-Scene), există deja un manager script care are deja setat license key-ul pentru ManoMotion. | + | ==== Overview laborator ==== |
- | <note important>**Indiferent de proiect, dacă acesta folosește ManoMotion, trebuie să aveți conexiune la Internet** – validarea license key-ului se realizează cu server-ele companiei la pornirea aplicației!</note> | + | În cadrul acestui laborator: |
+ | * Prezentăm pe scurt modalitatea de integrare a plugin-ului într-un proiect de Unity | ||
+ | <note important>Google Cardboard XR Plugin for Unity este deja intergrat și configurat (pentru Android).Quickstart-ul pentru setup se poate găsi aici: https://developers.google.com/cardboard/develop/unity/quickstart </note> | ||
+ | * Testăm demo sample-ul pentru a valida funcționarea corectă a plugin-ului | ||
+ | * Implementăm cateva feature-uri pentru un joc simplu (balloon popper), ce funcționează pe conceptul de gaze interaction | ||
- | Următorii pași nu sunt necesari în cadrul acestui laborator, dar ilustrează modalitatea de adăugare a package-ului ManoMotion în proiect, generarea și inserarea license key-ului (în framework este deja făcut setup-ul și se foloște un license key). | + | <note tip>În mod ideal, testarea funcționalităților din laborator se face folosind un dispozitiv de tip holder VR pentru smartphone, dar se poate testa și în absența acestuia. De asemenea, nu este necesară folosirea unui joystick pentru mobile.</note> |
- | - Creați-vă un cont pe https://www.manomotion.com. Necesar pentru descărcarea unity package-ului și accesarea documentației | + | În continuare puteți studia un demo ce prezintă laboratorul cu task-urile rezolvate (fără bonus-uri): |
- | - Descărcați unity package de aici https://developer.manomotion.com/products-download/. **Note:** În laborator s-a folosit “CE & AR Foundation” | + | |
- | - De pe pagina https://developer.manomotion.com/my-account/licenses/ creați-vă un license key. Trebuie să vă introduceți **Bundle ID**-ul aplicației (se găsește în Project Settings > Player > Package Name), precum și target platform-ul (Android sau iOS) | + | |
- | - Importați unity package-ul (setările de proiect ar trebui să fie realizate automat – în caz contrar, folosiți quickstart guide-ul de aici https://developer.manomotion.com/documentation/) | + | |
- | - Pe scena demo, sau una creată de voi cu suport pentru ManoMotion, pe script-ul **ManoMotionManager** adaugați-vă license key-ul general la pasul 3 | + | |
- | ==== ManoMotion SDK – Basic features ==== | + | <video here, eventually> |
- | {{ :irva:laboratoare:xr-test-scene-demo.gif?500 |}} | + | ==== Testarea scenei sample ==== |
- | Un proiect ce folosește ManoMotion se utilizează de camera smartphone-ului ca input – SDK-ul procesează fluxul de frame-uri primite de la camera and does its magic (detecție mână & gesturi). | + | * Mergeți în File > Build Settings și asigurați-vă că platforma pentru care doriți să faceți build este corectă. În caz contrar, faceți switch pe platforma dorită |
+ | * Vom testa scena Assets -> Samples -> Google Cardboard XR Plugin for Unity -> 1.22.0 -> Hello Cardboard -> Scenes -> HelloCardboard. Mergeți în File -> Build Settings și setați această scenă ca fiind singura activă (folosing checkbox-ul) în panoul de Scenes In Build | ||
+ | * În continuare, puteți crea un Build pe care să-l testați pe telefon | ||
- | Ne putem folosi destul de ușor de informația oferită de SDK – acesta setează valorile unor structuri de date (enums) pe care le putem interoga per frame. | + | Scena demo sample: |
- | Informația oferită este de mai multe tipuri, împărțită pe o serie de clase: | + | {{ :irva:laboratoare:l6_sample-scene.png?300 |}} |
- | === ManoClass === | + | Ierarhia scenei sample: |
- | Reprezintă clase “generale” de detecție, valori posibile: | + | {{ :irva:laboratoare:l6_sample-hierarchy.png?200 |}} |
- | <code c#> | + | === Testarea scenei sample === |
- | ManoClass.NO_HAND | + | |
- | ManoClass.GRAB_GESTURE | + | |
- | ManoClass.POINTER_GESTURE | + | |
- | ManoClass.PINCH_GESTURE | + | |
- | </code> | + | |
- | === ManoGestureTrigger === | + | * **CubeRoom** reprezinta modelul envroment-ului scenei |
+ | * **Treasure** reprezinta un obiect interactibil – daca îl studiați în inspector, veți observa că are atașat un script de tip **ObjectController** | ||
+ | * Camera are un obiect copil numit **CardboardReticlePointer** ce reprezintă reticle-ul / crosshair-ul direcției de vizualizare. Script-ul atașat pe acesta interacționează cu script-urile de tip **ObjectController**, căruia îi transmite mesaje de tip **OnPoinerEnter** și **OnPointerExit**, ceea ce denotă acțiunea de gaze (privire) asupra obiectelor | ||
- | Acestea sunt gesture de tip trigger – De exemplu, momentul (sau frame-ul) în care s-a detectat un “grab”, adică SDK-ul a detectat gestul de tip închidere pumn. Alt exemplu este un gest de tip “release”, care este true în frame-ul în care s-a detectat gestul de deschidere a pumnului. Valori posibile: | + | ==== Implementarea jocului ==== |
- | <code C#> | + | Veți avea de implementat un joculeț în care se spawnează în mod contnuu baloane, care pot fi sparte dacă player-ul le privește pentru un timp îndelungat – așadar, ne folosim de acest concept de gaze interaction. O parte a jocului este deja implementată, voi va trebui sa urmăriți todo-urile din cod pentru rezolva complet laboratorul. |
- | ManoGestureTrigger.NO_GESTURE | + | |
- | ManoGestureTrigger.CLICK | + | |
- | ManoGestureTrigger.RELEASE_GESTURE | + | |
- | ManoGestureTrigger.GRAB_GESTURE | + | |
- | ManoGestureTrigger.PICK | + | |
- | ManoGestureTrigger.DROP | + | |
- | </code> | + | |
- | === ManoGestureContinuous === | + | * Deschideți scena Assets -> L6_GoogleCardboard -> Scenes -> L6_BalloonPopper |
- | Gesturi continue, anume cele care persistă pe mai multe frame-uri – l gestul de tip “closed hand” este detectat în toate frame-urile în care este detectată o mână cu pumnul strâns. Valori posible: | + | {{ :irva:laboratoare:l6_game-hierarchy.png?200 |}} |
- | <code C#> | + | * **BaloonSpawner** este obiectul care va instanția baloanele în scenă. Acesta se află în zona podelei scenei. Are o componentă de tip BoxCollider, în volumul căreia trebuie instanțiate baloanele la locații random |
- | ManoGestureContinuous.NO_GESTURE | + | * **BaloonController** (nu se regăsește în ierarhie, este un script atașat prefab-ului ‘Baloon’) reprezintă obiectul de tip balon – acesta trebuie să fie translatat pe Y și va conține logica de interacțiune cu reticle-ul player-ului |
- | ManoGestureContinuous.HOLD_GESTURE | + | * **BalloonPopper** are atașat un script ce distruge baloanele dacă există overlap cu collider-ul obiectelor de tip balon. Acesta este definit în zona de tavan a scenei |
- | ManoGestureContinuous.OPEN_HAND_GESTURE | + | * **ScoreCanvas** conține logică pentru scor și poate seta textul unui element de UI definit în worldspace |
- | ManoGestureContinuous.OPEN_PINCH_GESTURE | + | |
- | ManoGestureContinuous.CLOSED_HAND_GESTURE | + | |
- | ManoGestureContinuous.POINTER_GESTURE | + | |
- | </code> | + | |
- | + | ||
- | === HandSide === | + | |
- | + | ||
- | Specifică ce parte a mâinii este detectată – palma sau dosul palmei. Valori posibile: | + | |
- | + | ||
- | <code C#> | + | |
- | HandSide.None | + | |
- | HandSide.Backside | + | |
- | HandSide.Palmside | + | |
- | </code> | + | |
- | + | ||
- | ==== Cum extragem informațiile de hand tracking și gestures? ==== | + | |
- | + | ||
- | <code C#> | + | |
- | // Detected hand information | + | |
- | HandInfo handInfo = ManomotionManager.Instance.Hand_infos[0].hand_info; | + | |
- | + | ||
- | // Detected gesture information | + | |
- | GestureInfo gestInfo = handInfo.gesture_info; | + | |
- | + | ||
- | ManoClass manoClass = gestInfo.mano_class; // Gesture class | + | |
- | ManoGestureTrigger gestTrigger = gestInfo.mano_gesture_trigger; // Trigger gesture | + | |
- | ManoGestureContinuous gestCont = gestInfo.mano_gesture_continuous; // Continuous gesture | + | |
- | HandSide handSide = gestInfo.hand_side; // Hand side | + | |
- | int gestureState = gestInfo.state; // Gesture state | + | |
- | Vector3 palmPosNorm = handInfo.tracking_info.palm_center; // Norm. screen coords [0...1] | + | |
- | + | ||
- | /** To get screen coords in pixels, multiply 'palmPosNorm' x/y with Screen.width, Screen.height */ | + | |
- | </code> | + | |
- | + | ||
- | ==== Cum putem folosi informațiile extrase? ==== | + | |
- | + | ||
- | În principal, aceste informații înlocuiesc input-ului, așadar am putea testa pe Update(), de exemplu: | + | |
- | + | ||
- | <code C#> | + | |
- | void Update() | + | |
- | { | + | |
- | // Grab hand info from ManoMotion's SDK | + | |
- | HandInfo handInfo = ManomotionManager.Instance.Hand_infos[0].hand_info; | + | |
- | + | ||
- | if(handInfo.gesture_info.mano_gesture_trigger == ManoGestureTrigger.GRAB_GESTURE) | + | |
- | { | + | |
- | // Do something only on the frame this is true | + | |
- | } | + | |
- | + | ||
- | if(handInfo.gesture_info.mano_gesture_continuous == ManoGestureContinuous.OPEN_HAND_GESTURE) | + | |
- | { | + | |
- | // Do something every frame this is true | + | |
- | } | + | |
- | } | + | |
- | </code> | + | |
- | + | ||
- | ==== Detalii proiect laborator ==== | + | |
- | + | ||
- | Proiectul are deja partea de AR configurată precum și baza unui joc (clonă simplified **Fruit Ninja**), la care va trebui să implementați câteva feature-uri. | + | |
- | + | ||
- | Aplicația de laborator este configurată într-o serie de etape, care ajută la configurarea spațiului AR de joc. Acestea sunt: | + | |
- | + | ||
- | * **Etapa 1**, cea de **plane detection** | + | |
- | * **Etapa 2**, cea de **instanțiere game scene AR**. Acest pas se realizează prin efectuarea unui gest de tip **Grab** peste un plan detectat – se realizează un raycast și se instanțiază scena de joc | + | |
- | * **Etapa 3**, cea de **ajustări** – se poate modifica rotația si scalarea scenei | + | |
- | * **Etapa 4**, cea de **joc** – în varianta nerezolvată, ar trebui să înceapă să fie instanțiatie la intervale random de timp obiecte 3D (fructe) - nu se poate realiza interacțiunea cu acestea | + | |
- | + | ||
- | **Script-uri** (se vor explica cele care sunt relevante): | + | |
- | + | ||
- | * SetupScripts | + | |
- | * **ARGameInitCanvasController** | + | |
- | * **ARInitController** – coordonează întreg procesul de setup AR și implementează funcțiile apelate de către butoanele de pe UI | + | |
- | * **ARSetupPhasesController** – coordonează tranzițiile între etapele de inițializare | + | |
- | * **Globals** | + | |
- | * GameScripts | + | |
- | * **[TODO] CursorPositionController** – Setează poziția unui cursor (obiect 3D care va urmări poziția mâinii pe ecran) | + | |
- | * **FruitController** | + | |
- | * **[TODO] FruitSpawner** – Coordonează procesul de spawning al fructelor | + | |
- | * **[TODO] HandGestureController** – Detectează o serie de gesturi diferite și modifică logica jocului pe baza acestora | + | |
==== Task-uri ==== | ==== Task-uri ==== | ||
- | **1.** Înainte de a lucra la joculețul propus, vă recomandăm mai întâi să testați scena demo oferită de către cei de la ManoMotion. Aceasta se găsește în **Assets > ManoMotion ARFoundation > Scenes > ManoMotion SDK CE ARFoundation Features** | + | - Realizați un build folosing scena sample din plugin – validați funcționarea corectă a acestui build – ar trebui sa aveți un render stereoscopic, să se realizeze head tracking-ul, iar obiectul ‘Treasure’ din scenă ar trebui să-și schime culoarea dacă reticle-ul player-ului interacționează cu aceasta |
- | + | - Instanțiați obiectele de tip balon din script-ul de spawner. Calculați, de asemenea, poziția acestora de instanțiere | |
- | <note important>Nu uitați să adăugați scena și s-o setați activă în Build Settings!</note> | + | - Realizați translația baloanelor instanțiate – în cel mai simplu mod, translatați-le cu o viteză constantă pe axa Y |
- | + | - Implementați mecanica de spargere a baloanelor – întâi, setați flag-ul ce denotă faptul că un balon este privit (targeted), iar apoi, implementați logica de timer. În esență, atât timp cât balonul este privit, acest timer trebuie incrementat – daca timpul contorizat este mai mare decât o limită impusă, spargeți balonul folosind metodele deja implementate | |
- | <note tip>Testați funcționalitățile din meniul aplicaței (după build) pentru a vă familiariza cu diversele gesturi care pot fi detectate. Aveți un buton de meniu din care puteți activa/dezactiva diverse feature-uri</note> | + | - Implementați funcționalitatea de scor – un balon spart de player reprezintă un punct primit, un balon spart de catre BalloonPopper reprezintă un punct scăzut. **ScoreController** și **BalloonPopper** conțin todo-urile relevante acestui task |
- | + | ||
- | În cazul în care activați toate feature-urile din scena demo, ar trebui sa obțineți o scenă similara cu cea prezentată mai jos: | + | |
- | + | ||
- | {{ :irva:laboratoare:mano-demoscene.gif?500 |}} | + | |
- | + | ||
- | **2.** În cazul în care nu au fost probleme, faceți switch la scena de laborator (**L6_Scene**) și realizați un build. Citiți cu atenție etapele de inițializare – pasul acesta este încheiat dacă instațiați scena de joc iar fructele încep să se spawneze. | + | |
- | + | ||
- | **3.** Pentru a tăia fructele, vă este oferit un obiect care ar trebui să urmărească poziția mâinii (mai exact, acest obiect de tip cursor este numit “**Spikeball_Cursor**” și se găsește în prefab-ul “**GameScene**” din **Assets > Prefabs > L6_ManoMotion**). Implementarea va trebui realizată în script-ul **CursorPositionController**. Rezultat corect: Obiectul cursor urmărește poziția mâinii și poate tăia fructele instanțiate în scenă. Urmăriți todo-urile din script. | + | |
- | + | ||
- | **4.** Va trebui să implementați diverse gesturi pentru a altera logica jocului. De exemplu, în frame-urile în care este detectat podul palmei, opriți spawning de fructe. Pentru detalii, urmăriți todo-urile din script-ul **HandGestureController** | + | |
- | + | ||
- | **5.** Pentru fiecare frame în care se detectează gestul de tip continuu **CLOSED_HAND_GESTURE**, creșteți spawn rate-ul de 20 de ori. Pentru detalii, urmăriți todo-urile din script-ul **HandGestureController** | + | |
- | + | ||
- | **6.** Când este detectat gestul de trigger de tip **PICK**, realizați o implementare prin care să “tăiați” (distrugeți) toate fructele instanțiate în acel moment în scena. Nu folosiți direct Destroy() pe ele, există o funcție deja implementată în controller-ul de fructe (use that!). Pentru detalii, urmăriți todo-urile din script-ul **HandGestureController** | + | |