This shows you the differences between two versions of the page.
irva:laboratoarevr:03 [2024/10/12 21:57] andrei.lapusteanu Added GIFs |
irva:laboratoarevr:03 [2025/09/28 02:00] (current) andrei.lapusteanu Finished new version |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laborator VR 03. SteamVR. Advanced input ====== | ====== Laborator VR 03. SteamVR. Advanced input ====== | ||
- | În acest laborator vom studia câteva aspecte mai avansate legate de input - cum îl putem citi în cod, cum ne putem defini acțiuni noi / custom - veți reuni aceste aspecte în implementarea unui gravity gun! | + | În acest laborator vom studia câteva aspecte mai avansate legate de input - cum îl putem citi în cod, cum ne putem defini acțiuni custom - veți reuni aceste aspecte în implementarea unui gravity gun! |
<note warning> | <note warning> | ||
Line 43: | Line 43: | ||
Noul sistem de input abstractizează partea de testare manuală a acestor input-uri prin **mapping-uri** și **acțiuni**. | Noul sistem de input abstractizează partea de testare manuală a acestor input-uri prin **mapping-uri** și **acțiuni**. | ||
- | Un **mapping** definește un set de acțiuni legate de anumite input-uri **fizice** (cum ar fi tastatura, mouse-ul, controller-ele, etc.). Practic, un mapping este o **schemă de control** care asociază diferite acțiuni cu diverse metode de input. Puteți să vă gândiți la un mapping ca la modul în care un player interacționează cu jocul în funcție de context. Câteva exemple de mapping-uri: | + | Un **mapping** definește un set de acțiuni legate de anumite input-uri **fizice** (cum ar fi tastatura, mouse-ul, controllerele, etc.). Practic, un mapping este o **schemă de control** care asociază diferite acțiuni cu diverse metode de input. Puteți să vă gândiți la un mapping ca la modul în care un player interacționează cu jocul în funcție de context. Câteva exemple de mapping-uri: |
* **MovementOnFoot** pentru mișcare pedestră (WASD pe tastatură sau joystick pe un controller) | * **MovementOnFoot** pentru mișcare pedestră (WASD pe tastatură sau joystick pe un controller) | ||
* **MovementInCar** pentru condusul unei mașini (**aceleași taste WASD** pe tastatură sau joystick pe un controller, dar într-un alt context!) | * **MovementInCar** pentru condusul unei mașini (**aceleași taste WASD** pe tastatură sau joystick pe un controller, dar într-un alt context!) | ||
- | * **MovementInBoat** pentru navigarea cu o barcă. | + | * **MovementInBoat** pentru navigarea cu o barcă |
O **acțiune** reprezintă o interacțiune definită de utilizator care poate fi activată prin diverse tipuri de input-uri. Acțiunile se pot lega la una sau mai multe intrări fizice printr-un **binding**. | O **acțiune** reprezintă o interacțiune definită de utilizator care poate fi activată prin diverse tipuri de input-uri. Acțiunile se pot lega la una sau mai multe intrări fizice printr-un **binding**. | ||
Line 58: | Line 58: | ||
{{ :irva:laboratoarevr:irva_2024_vr_l3_newinputsystem.png?700 |}} | {{ :irva:laboratoarevr:irva_2024_vr_l3_newinputsystem.png?700 |}} | ||
- | În final, următorul cod prezintă modul de utilizare al acestui sistem. Comentariile din cod ar trebuie să fie explicative. | + | În final, următorul snippet prezintă modul de utilizare al acestui sistem. Comentariile din cod ar trebuie să fie explicative. |
<code c#> | <code c#> | ||
Line 95: | Line 95: | ||
===== Import schelet laborator ===== | ===== Import schelet laborator ===== | ||
- | * Importați ultima versiune a pachetului ''WIP_NAME'' care se găsește în folder-ul **UnityPackages** din folder-ul root al proiectului | + | * Importați ultima versiune a pachetului ''IRVA_L3_VR_SteamVR_Skeleton'' care se găsește în folder-ul **UnityPackages** din folder-ul root al proiectului |
* Folder-ul **Assets -> L3_VR_SteamVR_Advanced** conține asset-urile suport pentru acest laborator. Deschideți scena ''L3_VR_SteamVR_GravityGun'' | * Folder-ul **Assets -> L3_VR_SteamVR_Advanced** conține asset-urile suport pentru acest laborator. Deschideți scena ''L3_VR_SteamVR_GravityGun'' | ||
Line 129: | Line 129: | ||
// - `SteamVR_Input_Sources` can be used to set a specific device to read from. In this case any device which has this action. | // - `SteamVR_Input_Sources` can be used to set a specific device to read from. In this case any device which has this action. | ||
var grabPinchState = SteamVR_Actions._default.GrabPinch.GetState(SteamVR_Input_Sources.Any); | var grabPinchState = SteamVR_Actions._default.GrabPinch.GetState(SteamVR_Input_Sources.Any); | ||
- | Debug.Log($"[SteamVRInputActionsTesting] grabPinchState = {grabPinchState}"); | + | Debug.Log($"[SteamVRInputActionsTesting] Polling: grabPinchState = {grabPinchState}"); |
} | } | ||
} | } | ||
Line 158: | Line 158: | ||
| | ||
// Method called when `onChange` from the `GrabPinch` is invoked. | // Method called when `onChange` from the `GrabPinch` is invoked. | ||
- | private void OnGrabPinchChanged(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource, bool newState) | + | private void OnGrabPinchChanged(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource, bool grabPinchState) |
{ | { | ||
- | Debug.Log($"[SteamVRInputActionsTesting] fromAction = {fromAction}, fromSource = {fromSource}, newState = {newState}"); | + | Debug.Log($"[SteamVRInputActionsTesting] Events: grabPinchState = {grabPinchState}"); |
} | } | ||
} | } | ||
Line 176: | Line 176: | ||
==== Task-ul vostru ==== | ==== Task-ul vostru ==== | ||
- | Pentru a exersa aceste aspecte implementați una din cele două metode prezentate mai sus în script-ul ''SteamVRInputActionsTesting'' pentru acțiunea de **GrabPinch** și testați-o (similar GIF-urilor prezentate mai sus). | + | Pentru a exersa aceste aspecte implementați una din cele două metode prezentate mai sus în script-ul ''SteamVRInputActionsTesting'' atât pentru acțiunea de **GrabPinch** cât și pentru **GrabGrip** și testați-o (similar GIF-urilor prezentate mai sus). |
==== Binding-uri în SteamVR ==== | ==== Binding-uri în SteamVR ==== | ||
Line 186: | Line 186: | ||
{{ :irva:laboratoarevr:irva_2024_vr_l3_steamvrbindings1.png?500 |}} | {{ :irva:laboratoarevr:irva_2024_vr_l3_steamvrbindings1.png?500 |}} | ||
- | Editați binding-ul curent (click pe **Edit** de pe **oculus_touch (Local changes)**. | + | Editați binding-ul curent sau creați unul noi |
* În noua ferestră puteți lega **butoanele fizice** de **acțiuni** (acesta este în esență un **binding**) | * În noua ferestră puteți lega **butoanele fizice** de **acțiuni** (acesta este în esență un **binding**) | ||
Line 195: | Line 195: | ||
<note tip> | <note tip> | ||
- | * Ca să legăm informația învățată: Acest **Grab Pinch** este o **acțiune** binded pe butonul de **Trigger**, conținută în **action set-ul default**. | + | * Ca să legăm informația învățată: Acest **Grab Pinch** este o **acțiune** binded pe butonul de **Trigger**, conținută în **action set-ul default** |
- | * În spate, SteamVR va genera cod care ne permite să referențiem în script-urile noastre aceste elemente. | + | * În spate, SteamVR va genera cod care ne permite să referențiem în script-urile noastre aceste elemente |
* Pe scurt, acesta este motivul pentru care putem referenția în cod ''SteamVR_Actions._default.GrabPinch'' | * Pe scurt, acesta este motivul pentru care putem referenția în cod ''SteamVR_Actions._default.GrabPinch'' | ||
</note> | </note> | ||
Line 211: | Line 211: | ||
Pentru început, este necesar să vă definiți întâi o nouă acțiune - în acest exemplu vom crea în fereastra **SteamVR Input** o nouă acțiune **TouchTrigger** în **action set-ul default**. | Pentru început, este necesar să vă definiți întâi o nouă acțiune - în acest exemplu vom crea în fereastra **SteamVR Input** o nouă acțiune **TouchTrigger** în **action set-ul default**. | ||
- | * Definiți noua acțiune | + | * Definiți noua acțiune (rețineți pentru viitoare binding-uri secțiunea **Type** - momentan pentru acest exemplu ''boolean'' este tipul dorit) |
* Apăsați pe **Save and generate** | * Apăsați pe **Save and generate** | ||
Line 236: | Line 236: | ||
{{ :irva:laboratoarevr:irva_2024_vr_l3_steamvrbindings6.png?400 |}} | {{ :irva:laboratoarevr:irva_2024_vr_l3_steamvrbindings6.png?400 |}} | ||
- | Awesome 🎉! În acest moment toată logica necesară acestei acțiuni (și al binding-ului) este finalizată. | + | Awesome 🎉! În acest moment toată logica necesară acestei acțiuni (și a binding-ului) este finalizată. |
==== Task-ul vostru ==== | ==== Task-ul vostru ==== | ||
Line 244: | Line 244: | ||
{{ :irva:laboratoarevr:irva_2024_vr_steamvr_l3_3.gif?500 |}} | {{ :irva:laboratoarevr:irva_2024_vr_steamvr_l3_3.gif?500 |}} | ||
+ | |||
+ | ==== Extra challenge ==== | ||
+ | |||
+ | Pentru a testa cunoștințele acumulate până în acest punct, încercați să: | ||
+ | * Creați un nou **action** și **binding** pentru joystick-ul controller-ului (nu acțiunea de touch sau apăsarea acestuia, cu pentru deplasarea joystick-ului sus-jos-stânga-dreapta) | ||
+ | * Completați ''SteamVRInputActionsTesting'' pentru a trata nou binding și afișați în consolă valorile joystick-ului | ||
+ | |||
+ | <note> | ||
+ | Ce tip de date ar trebui să aiba această acțiune 🤔? Ce valori obțineți (ce range)? | ||
+ | </note> | ||
===== Rendering stereo ===== | ===== Rendering stereo ===== | ||
Line 252: | Line 262: | ||
* **Single Pass Instanced**: La fel cu **Single Pass** dar folosește și tehnica de **GPU instancing** (aceasta grupează mai eficient draw call-uri, reducându-le numărul) | * **Single Pass Instanced**: La fel cu **Single Pass** dar folosește și tehnica de **GPU instancing** (aceasta grupează mai eficient draw call-uri, reducându-le numărul) | ||
- | Metodele de tip **single pass** sunt cele mai eficiente din punct de vedere computațional, dar pot suferi de **incompatibilități cu diverse shadere**. Un exemplu folosit în acest laborator este componenta de tip **LineRenderer**, care nu este desenată corect în cazul desenării single pass. | + | Metodele de tip **single pass** sunt cele mai eficiente din punct de vedere computațional, dar pot suferi de **incompatibilități cu diverse shadere**. <del>Un exemplu folosit în acest laborator este componenta de tip **LineRenderer**, care nu este desenată corect în cazul desenării single pass.</del> |
- | <note tip>Pentru acest laborator va trebui să schimbați din **Edit -> Project Settings -> XR Plug-In Management -> OpenVR Stereo Rendering Mode** în **Multipass**.</note> | + | <note tip> |
+ | <del>Pentru acest laborator va trebui să schimbați din **Edit -> Project Settings -> XR Plug-In Management -> OpenVR Stereo Rendering Mode** în **Multipass**.</del> | ||
+ | |||
+ | Update: În noile versiuni as of writing (Unity 6.2, SteamVR 2.8.0) această problemă nu mai este prezentă. | ||
+ | </note> | ||
<note important> | <note important> | ||
- | Este recomandat să dezvoltați aplicațiile în modurile cele mai eficiente (single pass) și să rețineți această setare pentru situații similare în viitor. În cadrul acestui laborator compromisul folosind Multipass este preferat pentru a ne ușura munca. | + | Este recomandat să dezvoltați aplicațiile în modurile cele mai eficiente (single pass) și să rețineți această setare pentru situații similare în viitor. <del>În cadrul acestui laborator compromisul folosind Multipass este preferat pentru a ne ușura munca.</del> |
</note> | </note> | ||
Line 264: | Line 278: | ||
Pentru a aplica cunoștințele pe care le-ați învățat pe parcursul acest laborator, va trebuie să finalizați implementarea unui **gravity gun**. | Pentru a aplica cunoștințele pe care le-ați învățat pe parcursul acest laborator, va trebuie să finalizați implementarea unui **gravity gun**. | ||
- | Logic de funcționare a acestui **gravity gun** este deja implimentată, voi va trebui să configurați și să legați input-ului necesar folosind **acțiuni** și **binding-uri**. | + | Logica de funcționare a acestui **gravity gun** este deja implimentată, voi va trebui să configurați și să legați input-ului necesar folosind **acțiuni** și **binding-uri**. |
- | Obiectul **[GracityGun]** din scena suport este de tip **Throwable**, așadar îi puteți face grab. | + | Obiectul **[GravityGun]** din scena suport este de tip **Throwable**, așadar îi puteți face grab. |
<note tip> | <note tip> | ||
Line 277: | Line 291: | ||
* Dacă nu este apăsat nici un alt buton, nu trebuie să faceți nimic | * Dacă nu este apăsat nici un alt buton, nu trebuie să faceți nimic | ||
* Dacă butonul de **trigger** este **atins (touched)**, iar un obiect este în raza sa de acțiune, are loc un efect de **snap** al acelui obiect - acesta este adus și fixat de arma gravitațională | * Dacă butonul de **trigger** este **atins (touched)**, iar un obiect este în raza sa de acțiune, are loc un efect de **snap** al acelui obiect - acesta este adus și fixat de arma gravitațională | ||
- | * Dacă butonul de **trigger** este lăsat liber (eveniment-ul eferent **touch-ului** trece din ''true'' în ''false'', obiectul snapped este **tossed**, anume lăsat să cadă liber | + | * Dacă butonul de **trigger** este lăsat liber (starea **touch-ului** trece din ''true'' în ''false''), obiectul snapped este **tossed**, anume lăsat să cadă liber |
* Dacă un obiect este snapped, iar butonul de **trigger** este **apăsat (click)**, obiectul este **propulsat (throw)** | * Dacă un obiect este snapped, iar butonul de **trigger** este **apăsat (click)**, obiectul este **propulsat (throw)** | ||
Line 287: | Line 301: | ||
* În ''GravityGunController'' aveți metodele ''SnapObject'', ''TossObject'' și ''ThrowObject'' deja implementate - acestea vor trebui apelate pe baza input-ului definit de voi | * În ''GravityGunController'' aveți metodele ''SnapObject'', ''TossObject'' și ''ThrowObject'' deja implementate - acestea vor trebui apelate pe baza input-ului definit de voi | ||
* Veți avea nevoie în esență de **2 acțiuni** (de ex. **GravityGunTouch** și **GravityGunClick**) | * Veți avea nevoie în esență de **2 acțiuni** (de ex. **GravityGunTouch** și **GravityGunClick**) | ||
- | * Va trebui să vă definiți **2 binding-uri** (de ex. pe evenimentele de tip **Click** și **Touch** din meniul de bind-uri SteamVR) | + | * Va trebui să vă definiți **2 binding-uri** (de ex. pe evenimentele de tip **Click** și **Touch** din meniul de bind-uri SteamVR) pentru **butonul fizic de trigger** al controller-ului |
* În ''GravityGunController'' va trebui să implementați logica pentru input-urile definite anterior | * În ''GravityGunController'' va trebui să implementați logica pentru input-urile definite anterior | ||
* Dacă optați pentru polling pe ''Update'', vedeți ce metode de input trebuie să folosiți (de ex. ''GetStateUp'', ''GetStateDown'', etc.) | * Dacă optați pentru polling pe ''Update'', vedeți ce metode de input trebuie să folosiți (de ex. ''GetStateUp'', ''GetStateDown'', etc.) | ||
Line 300: | Line 314: | ||
* Faceți referire la secțiunea //My first (new) SteamVR binding// pentru explicații suplimentare | * Faceți referire la secțiunea //My first (new) SteamVR binding// pentru explicații suplimentare | ||
- Finalizați logica pentru **gravity gun** | - Finalizați logica pentru **gravity gun** | ||
- | * Definiți-vă noile acțiuni și binding-uri | + | * Definiți-vă noile acțiuni și binding-uri, legați-le la butonul de trigger al controller-ului |
* Legați input-ul în script-ul ''GravityGunController'' și apelați metodele ''SnapObject'', ''TossObject'' și ''ThrowObject'' pe baza acestuia | * Legați input-ul în script-ul ''GravityGunController'' și apelați metodele ''SnapObject'', ''TossObject'' și ''ThrowObject'' pe baza acestuia | ||
* Faceți referire la capitolul //Gravity gun// (și subcapitolele acestuia) pentru explicații suplimentare | * Faceți referire la capitolul //Gravity gun// (și subcapitolele acestuia) pentru explicații suplimentare | ||
- **[✨Bonus✨]** Implementați o mecanică de **rotire** a obiectului snapped de către gravity gun folosind **stick-ul direcțional (joystick)** al controller-ului | - **[✨Bonus✨]** Implementați o mecanică de **rotire** a obiectului snapped de către gravity gun folosind **stick-ul direcțional (joystick)** al controller-ului | ||
* Modalitatea de transformare a input-ului oferit de joystick în rotația efectivă este la latitudinea voastră (mai precis trebuie să vedeți față de ce axe (X, Y, Z, locale, globale) rotați bazat pe valoarea input-ului | * Modalitatea de transformare a input-ului oferit de joystick în rotația efectivă este la latitudinea voastră (mai precis trebuie să vedeți față de ce axe (X, Y, Z, locale, globale) rotați bazat pe valoarea input-ului | ||
- | * Modulați viteza de rotație în funcție de valoarea analogică (0-1) oferită de joystick | + | * Modulați viteza de rotație în funcție de valoarea analogică oferită de joystick |