Î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!
Sistemul de input folosit în SteamVR se bazează pe acțiuni.
Înainte să discutăm despre el, vom prezenta pe scurt cele 2 paradigme de folosire a input-ului în Unity.
În sistem legacy de input din Unity testarea acțiunilor este destul de simplă în cod, dar are câteva limitări. În cel mai simplu mod, input-ul se poate testa prin polling-ul unor butoane de input specifice.
public class LegacyInputExample : MonoBehaviour { // Update is needed to poll every frame. private void Update() { // I want 3 buttons to call the same logic: LMB (mouse), Space (key), LCtrl (key). // In the legacy system, I need to hardcode the keycodes. if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.LeftControl)) { Debug.Log("[LegacyInputExample] Action performed!"); } } }
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:
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.
Pentru a folosi acest sistem de input:
În final, următorul cod prezintă modul de utilizare al acestui sistem. Comentariile din cod ar trebuie să fie explicative.
public class ActionsInputExample : MonoBehaviour { private InputActionAssetExample playerInputActions; private InputAction fireAction; // Initialize input asset. private void Awake() => playerInputActions = new InputActionAssetExample(); // Get the action `Fire` from the mapping `PlayerMapping`. Enable it & bind event. private void OnEnable() { fireAction = playerInputActions.PlayerMapping.Fire; fireAction.Enable(); fireAction.performed += FirePerformed; } private void OnDisable() { fireAction.Disable(); fireAction.performed -= FirePerformed; } // Called whenever any of the bindings defined for the `Fire` action are called. // No need for explicit checks or the `Update` method! private void FirePerformed(InputAction.CallbackContext context) => Debug.Log("Fired action!"); }
Sistemul de input din SteamVR nu se bazează în mod expres pe sistemul de input din Unity; SteamVR are un sistem propriu bazat pe acțiuni. Cu toate acestea, conceptele utilizate (acțiuni, mapări, evenimente) sunt foarte similare. Înțelegerea sistemului de input bazat pe acțiuni din Unity vă va ajuta să înțelegeți mai bine modul în care funcționează cel din SteamVR.
IRVA_L3_VR_SteamVR_Skeleton
care se găsește în folder-ul UnityPackages din folder-ul root al proiectuluiL3_VR_SteamVR_GravityGun
Această scenă conține prefab-ul de player, câteva mese pe care se află câteva obiecte, precum și un gravity gun.
Precum a fost menționat anterior, sistemul de input din SteamVR se bazează pe acțiuni.
Deschideți fereastra de editor din Window → SteamVR Input. Aici o să vedeți definite:
In cod puteți face referire atât la Action sets cât și la Actions. Pentru a învăța modul de utilizare, urmăriți următorii pași:
SteamVRInputActionsTesting
, pe care-l va trebui să-l completațiO metodă validă pentru a realiza acest task este prin polling. Urmăriți comentariile din snippet pentru detalii.
public class SteamVRInputActionsTesting : MonoBehaviour { private void Update() { // Explanation: // - From the `_default` mapping (action set), get the `GrabPinch` action's state via `GetState`. // - `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); Debug.Log($"[SteamVRInputActionsTesting] Polling: grabPinchState = {grabPinchState}"); } }
GetState
puteți să folosiți și alte metode, care vă pot indica tranziții de la true
la false
(sau invers), etc.
O altă metodă pentru a citi același input se bazează pe evenimente. Recomandăm această metodă întrucât face bypass polling-ului și considerăm că este un mod mai modular de a citi acest input.
public class SteamVRInputActionsTesting : MonoBehaviour { // Subscribe to event `onChange` from the `GrabPinch` contained in the `_default` action set // and call `OnGrabPinchChanged` on invocations. private void OnEnable() => SteamVR_Actions._default.GrabPinch.onChange += OnGrabPinchChanged; // Unsubscribe from event. private void OnDisable() => SteamVR_Actions._default.GrabPinch.onChange -= OnGrabPinchChanged; // Method called when `onChange` from the `GrabPinch` is invoked. private void OnGrabPinchChanged(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource, bool grabPinchState) { Debug.Log($"[SteamVRInputActionsTesting] Events: grabPinchState = {grabPinchState}"); } }
onChange
puteți să vă abonați și la alte evenimente, care vă pot indica tranziții de la true
la false
(sau invers), etc.
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 extinde funcționalitatea standard și a vă permite să ve definiți acțiuni noi, este necesar să folosiți sistemul de binding implementat în SteamVR.
Din mediul Window → SteamVR Input apăsați pe opțiunea Open binding UI. Ar trebui să vi să deschidă o nouă fereastră ce prezintă binding-ul curent pentru controller-ele pe care le folosiți.
Editați binding-ul curent (click pe Edit de pe oculus_touch (Local changes).
SteamVR_Actions._default.GrabPinch
În continuare veți învăța cum să vă creați propriile acțiuni. Pentru simplitate ne vom folosi de action set-ul default și de butonul fizic de Trigger.
Ca și exemplu, vom crea o nouă acțiune de atingere (touch) a trigger-ului
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.
În continuare trebuie să realizăm binding-ul.
Așadar, acest sistem be binding vă permite astfel să configurați comportamentul logic al butonului fizic.
Următorul pas necesar este configurarea acțiunii:
Awesome 🎉! În acest moment toată logica necesară acestei acțiuni (și al binding-ului) este finalizată.
Pentru a testa dacă această nouă acțiune a fost configurată corect, completați script-ul SteamVRInputActionsTesting
și afișați mesaje în consolă atunci când interogați această nouă acțiune TouchTrigger.
Update
sau folosind evenimente)În aplicațiile de VR dezvolatate cu Unity se poate seta parametrul Stereo Rendering Mode, care specifică modalitatea de desenare a scenei în realitate virtuală - acest aspect este controlabil întrucât în general există două ecrane (unul pentru fiecare ochi) care trebuie actualizate și există câteva moduri de bază:
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.
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.
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 [GravityGun] din scena suport este de tip Throwable, așadar îi puteți face grab.
După ce gravity gun-ul a fost grabbed, va trebui să implementați următorul comportament:
true
în false
, obiectul snapped este tossed, anume lăsat să cadă liber
Logica de funcționare este implementată în GravityGunController
, iar obiectele interactibile care interacționează cu gravity gun-ul implementează GravityGunObject
.
GravityGunController
aveți metodele SnapObject
, TossObject
și ThrowObject
deja implementate - acestea vor trebui apelate pe baza input-ului definit de voiGravityGunController
va trebui să implementați logica pentru input-urile definite anteriorUpdate
, vedeți ce metode de input trebuie să folosiți (de ex. GetStateUp
, GetStateDown
, etc.)onStateUp
, onStateDown
, etc.)SnapObject
, TossObject
și ThrowObject
pentru a finaliza implementareaSteamVRInputActionsTesting
logica de citire a input-ului pentru acțiunea GrabPinch folosind oricare dintre metodele prezentate (polling, evenimente). Afișați rezultatul în consolă pentru a confirma funcționareaSteamVRInputActionsTesting
logica de citire a input-ului. Afișați rezultatul în consolă pentru a confirma funcționareaGravityGunController
și apelați metodele SnapObject
, TossObject
și ThrowObject
pe baza acestuia