Ukazatele – MRTK2

Ukazatel

Tento článek vysvětluje, jak v praxi nakonfigurovat vstup ukazatele a reagovat na ně. Pokud chcete lépe porozumět tomu, jak ovládat více ukazatelů na vysoké úrovni, přečtěte si téma Architektura ukazatele.

Při zjištění nového kontroleru se ukazatele automaticky vytvoří za běhu. K ovladači lze připojit více než jeden ukazatel. Například s výchozím profilem ukazatele získá Windows Mixed Reality kontrolery jak čáru, tak parabolický ukazatel pro normální výběr a teleportaci.

Konfigurace ukazatele

Ukazatele jsou nakonfigurovány jako součást vstupního systému v MRTK prostřednictvím MixedRealityPointerProfile. Tento typ profilu je přiřazen k objektu MixedRealityInputSystemProfile v inspektoru konfigurace MRTK. Profil ukazatele určuje kurzor, typy ukazatelů, které jsou k dispozici za běhu, a způsob vzájemné komunikace těchto ukazatelů, aby se rozhodl, který z nich je aktivní.

  • Pointing Extent – definuje maximální vzdálenost, po kterou může ukazatel interagovat s objektem GameObject.

  • Namíření raycastových masek vrstvy – Toto je pole vrstvových masek podle priority, které určuje, se kterými možnými objekty GameObjects může daný ukazatel interagovat, a pořadí, ve kterém se má pokusit o interakci. To může být užitečné, pokud chcete zajistit, aby ukazatele nejprve interagovali s prvky uživatelského rozhraní před ostatními objekty scény. Příklad profilu ukazatele

Konfigurace možností ukazatele

Výchozí konfigurace profilu ukazatele MRTK zahrnuje následující třídy ukazatelů a přidružené předem připravené objekty. Seznam ukazatelů dostupných pro systém za běhu je definován v části Možnosti ukazatele v profilu ukazatele. Vývojáři můžou tento seznam využít k překonfigurování existujících ukazatelů, přidání nových ukazatelů nebo k jejich odstranění.

Příklad profilu možností ukazatele

Každá položka ukazatele je definována následující sadou dat:

  • Typ kontroleru – sada kontrolerů, pro které je ukazatel platný.

    • Například PokePointer je zodpovědný za "šťouchnutí" objektů prstem a je ve výchozím nastavení označen pouze jako podpůrný typ kloubového ovladače rukou. Ukazatele se vytvářejí pouze v případě, že je k dispozici kontroler, a zejména typ kontroleru definuje, s jakými řadiči lze tento prefab ukazatele vytvořit.
  • Handness – umožňuje vytvořit instanci ukazatele jenom pro určitou ruku (vlevo/vpravo).

Poznámka

Nastavením vlastnosti Odevzdání položky ukazatele na hodnotu None ji v podstatě zakážete ze systému jako alternativu k odebrání tohoto ukazatele ze seznamu.

  • Prefab pointer – tento prefab asset se vytvoří, když se začne sledovat kontroler odpovídající zadanému typu kontroleru a odevzdání.

K kontroleru je možné přidružit více ukazatelů. Například v DefaultHoloLens2InputSystemProfile systému (Assets/MRTK/SDK/Profiles/HoloLens2/) je kloubový ovladač ruky přidružený k pokePointeru, GrabPointeru a DefaultControllerPointeru (tj. paprskům rukou).

Poznámka

MRTK poskytuje sadu prefab ukazatelů v assets/MRTK/SDK/Features/UX/Prefabs/Pointers. Nový vlastní prefab lze sestavit, pokud obsahuje jeden ze skriptů ukazatele v Assets/MRTK/SDK/Features/UX/Scripts/Pointers nebo jiném skriptu implementované IMixedRealityPointer.

Konfigurace kurzoru

Kurzor pohledu je přímo konfigurovatelný prostřednictvím GazeCursorPrefab vlastnosti v editoru MixedRealityInputSystemProfile . Pokud chcete nakonfigurovat kurzor použitý pro jiné ukazatele, musíte změnit prefab použitý v CursorPrefab poli odpovídajícího BaseControllerPointer. Chcete-li změnit kurzor programově, upravte BaseCursor vlastnost odpovídajícího IMixedRealityPointer chování.

Vlastnost Prefab kurzoru

Příklady implementace chování kurzoru najdete v tématu Assets/MRTK/SDK/Features/UX/Prefabs/Cursors . Konkrétně DefaultGazeCursor poskytuje robustní implementaci změny grafiky kurzoru na základě kontextového stavu.

Výchozí třídy ukazatelů

Následující třídy jsou předdefinované ukazatele MRTK, které jsou k dispozici a definované ve výchozím profilu ukazatele MRTK uvedeném výše. Každý prefab ukazatele zadaný v části Assets/MRTK/SDK/Features/UX/Prefabs/Pointers obsahuje jednu z připojených komponent ukazatele.

Výchozí ukazatele MRTK

Ukazatele na dálku

LinePointer

LinePointer, třída základního ukazatele, nakreslí čáru ze zdroje vstupu (tj. kontroleru) ve směru ukazatele a podporuje jeden paprsek v tomto směru. Obecně platí, že podřízené třídy, jako ShellHandRayPointer jsou ukazatele teleportu a , se vytvářejí a využívají (které také kreslí čáry, které označují, kde teleportace skončí) místo této třídy, která primárně poskytuje společné funkce.

U ovladačů pohybu, jako jsou Oculus, Vive a Windows Mixed Reality, bude rotace odpovídat otáčení ovladače. U jiných ovladačů, jako jsou HoloLens 2 kloubové ruce, odpovídá otáčení polohovací pozici ruky poskytované systémem.

Čára ukazatele MRTK
CurvePointer

CurvePointer rozšiřuje třídu LinePointer tím, že umožňuje vícekrokové paprskové přetypování podél křivky. Tato základní třída ukazatele je užitečná pro zakřivené instance, jako jsou teleportační ukazatele, kde se čára konzistentně ohýbá do paraboly.

ShellHandRayPointer

Implementace ShellHandRayPointer, která se rozšiřuje od LinePointer, se používá jako výchozí pro profil ukazatele MRTK. Prefab DefaultControllerPointer implementuje ShellHandRayPointer třídu.

GGVPointer

GGVPointer, který se také označuje jako ukazatel pohledu/gesta/hlasu (GGV), podporuje vzhled HoloLensu ve stylu 1 a interakce klepnutí, a to především prostřednictvím pohledu a klepnutí vzduchem nebo interakce pohledu a hlasového výběru. Poloha a směr ukazatele GGV je řízen polohou a otáčením hlavy.

TouchPointer

TouchPointer je zodpovědný za práci se vstupem Unity Touch (tj. dotykovým displejem). Jedná se o "vzdálené interakce", protože když se dotknete obrazovky, vysadí se paprsek z fotoaparátu na potenciálně vzdálené místo ve scéně.

MousePointer

Myš MousePointer nasměruje obrazovku na svět raycast pro vzdálené interakce, ale pro myš místo dotykového ovládání.

Ukazatel myši

Poznámka

Podpora myši není ve výchozím nastavení v MRTK dostupná, ale je možné ji povolit přidáním nového zprostředkovatele vstupních dat typu MouseDeviceManager do vstupního profilu MRTK a přiřazením MixedRealityMouseInputProfile zprostředkovatele dat.

Blízké ukazatele

PokePointer

PokePointer se používá k interakci s herními objekty, které podporují "blízkou interakci dotykového ovládání". což jsou Objekty GameObjects s připojeným NearInteractionTouchable skriptem. V případě UnityUI tento ukazatel hledá NearInteractionTouchableUnityUIs. PokePointer používá SphereCast k určení nejbližšího dotykového prvku a slouží k napájení věcí, jako jsou stisknutelná tlačítka.

Při konfiguraci objektu GameObject s komponentou NearInteractionTouchable nezapomeňte nakonfigurovat parametr localForward tak, aby odkazoval mimo přední stranu tlačítka nebo jiného objektu, který by měl být dotykový. Také se ujistěte, že hranice dotykového objektu odpovídají hranicím dotykového objektu.

Užitečné vlastnosti ukazatele poke:

  • TouchableDistance: Maximální vzdálenost, ve které lze s dotykovým povrchem pracovat
  • Vizuály: Herní objekt používaný k vykreslení vizuálu prstu (prsten na prstu, ve výchozím nastavení).
  • Čára: Volitelná čára pro kreslení z prstu na aktivní vstupní plochu.
  • Poke Layer Masks – pole vrstvových masek s prioritou, které určuje, se kterými možnými objekty GameObject může ukazatel interagovat, a pořadí, ve kterém se má pokusit o interakci. Všimněte si, že GameObject musí mít také komponentu NearInteractionTouchable , aby bylo možné pracovat s ukazatelem poke.
Ukazatel poke
SpherePointer

SpherePointer používá UnityEngine.Physics.OverlapSphere k identifikaci nejbližšího NearInteractionGrabbable objektu pro interakci, což je užitečné pro "grabbable" vstup, jako ManipulationHandlerje . Podobně jako u funkčního PokePointer/NearInteractionTouchable páru musí herní objekt obsahovat komponentu NearInteractionGrabbable , která je skriptem, aby bylo možné pracovat s ukazatelem koule.

Uchopte ukazatel

Užitečné vlastnosti ukazatele koule:

  • Poloměr přetypování koule: Poloměr koule použité k dotazování na uchopitelné objekty.
  • Blízko okraje objektu: Vzdálenost v horní části poloměru přetypování sphere, která se má dotazovat na zjištění, jestli je objekt v blízkosti ukazatele. Total Near Object detection radius is Sphere Cast Radius + Near Object Margin
  • Úhel v blízkosti sektoru objektu: Úhel kolem dopředu osy ukazatele pro dotazování na blízké objekty. IsNearObject Vytvoří funkci dotazu jako kužel. Tato hodnota je ve výchozím nastavení nastavená na 66 stupňů, aby odpovídala chování Hololens 2.

Ukazatel koule byl změněn tak, aby se dotazovat pouze na objekty ve směru dopředu

  • Faktor vyhlazování blízko objektu: Faktor vyhlazování pro detekci blízkých objektů. Pokud je v poloměru blízkého objektu zjištěn objekt, dotazovaný poloměr se pak změní na Poloměr blízko objektu * (1 + faktor vyhlazování blízkého objektu), aby se snížila citlivost a ztížila se pro objekt opustit rozsah detekce.
  • Uchopte masky vrstvy – pole vrstvových masek s prioritou, které určuje, se kterými možnými objekty GameObject může ukazatel interagovat, a pořadí, ve kterém se má pokusit o interakci. Všimněte si, že objekt GameObject musí mít také objekt NearInteractionGrabbable pro interakci s SpherePointerem.

    Poznámka

    Vrstva prostorového povědomí je ve výchozím prefabu GrabPointeru poskytovaném MRTK zakázaná. To se provádí za účelem snížení dopadu na výkon při provádění dotazu překrývajícího se s prostorovou sítí. Můžete to povolit úpravou prefabu GrabPointer.

  • Ignore Colliders Not in FOV – Jestli se mají ignorovat kolidátory, které se můžou blížit ukazateli, ale ve skutečnosti ne ve vizuálu FOV. To může zabránit náhodnému uchopení a umožní zapnutí paprsků rukou, když můžete být blízko uchopení, ale nevidíte ho. Vizuální FOV se z důvodů výkonu definuje prostřednictvím kuželu místo typického frustum. Tento kužel je zarovnaný na střed a orientaci stejně jako frustum fotoaparátu s poloměrem, který se rovná polovině výšky displeje (neboli svislé FOV).
Ukazatel koule

Teleportování ukazatelů

  • TeleportPointer aplikace vyvolá žádost o teleport, když se provede akce (tj. stisknete tlačítko teleportu), aby se uživatel mohl přesunout.
  • ParabolicTeleportPointer vyvolá žádost o teleport, když je provedena akce (tj. je stisknuto tlačítko teleportu) s parabolickým paprskovým paprskem, aby bylo možné uživatele přesunout.
Parabolický ukazatel

Podpora ukazatelů pro platformy hybridní reality

Následující tabulka obsahuje podrobnosti o typech ukazatelů, které se obvykle používají pro běžné platformy v MRTK. POZNÁMKA: Na tyto platformy je možné přidat různé typy ukazatelů. Do virtuální reality můžete například přidat ukazatel Poke nebo Sphere. Kromě toho můžou zařízení VR s gamepadem používat ukazatel GGV.

Ukazatel OpenVR Windows Mixed Reality HoloLens 1 HoloLens 2
ShellHandRayPointer Platné Platné Platné
TeleportPointer Platné Platné
GGVPointer Platné
SpherePointer Platné
PokePointer Platné

Interakce s ukazateli prostřednictvím kódu

Rozhraní událostí ukazatele

MonoBehaviours, které implementují jedno nebo více z následujících rozhraní a jsou přiřazeny GameObject s Collider a budou přijímat události Interakce Ukazatele definované přidružené rozhraní.

Událost Popis Obslužná rutina
Před změnou fokusu / Změna fokusu Vyvoláno při ztrátě fokusu na herním objektu i na objektu, který ho získává pokaždé, když ukazatel změní fokus. IMixedRealityFocusChangedHandler
Vstup/ ukončení fokusu Aktivováno na herním objektu, který získává fokus, když do něj vstoupí první ukazatel, a na jednom, který fokus ztratí, když ho poslední ukazatel opustí. IMixedRealityFocusHandler
Ukazatel dolů / přetažení / nahoru / kliknutí Zvednuté na ukazatel sestavy stiskněte, přetáhněte ho a uvolněte. IMixedRealityPointerHandler
Dotykové ovládání spuštěno / aktualizováno / dokončeno Uchycené ukazateli pracujícími s dotykovým ovládáním, jako PokePointer by oznamovaly aktivitu dotykového ovládání. IMixedRealityTouchHandler

Poznámka

IMixedRealityFocusChangedHandler a IMixedRealityFocusHandler by měly být zpracovány v objektech, na které jsou vyvolány. Události fokusu je možné přijímat globálně, ale na rozdíl od jiných vstupních událostí globální obslužná rutina událostí neblokuje příjem událostí na základě fokusu (událost přijme globální obslužná rutina i odpovídající objekt v fokusu).

Události vstupu ukazatele v akci

Vstupní události ukazatele jsou rozpoznány a zpracovávány vstupním systémem MRTK podobným způsobem jako běžné vstupní události. Rozdíl je v tom, že události vstupu ukazatele jsou zpracovávány pouze objektem GameObject v fokusu ukazatelem, který aktivoval vstupní událost, stejně jako jakékoli globální obslužné rutiny vstupu. Běžné vstupní události jsou zpracovávány objekty GameObject fokus pro všechny aktivní ukazatele.

  1. Vstupní systém MRTK rozpozná vstupní událost, ke které došlo.
  2. Vstupní systém MRTK aktivuje příslušnou funkci rozhraní pro vstupní událost všem registrovaným globálním obslužným rutinám vstupu.
  3. Vstupní systém určuje, na který objekt GameObject je fokus pro ukazatel, který aktivoval událost.
    1. Vstupní systém využívá Event System Unity k vyvolání příslušné funkce rozhraní pro všechny odpovídající komponenty na zaměřeném Objektu GameObject.
    2. Pokud byla vstupní událost v libovolném okamžiku označena jako použitá, proces se ukončí a žádné další objekty GameObject nebudou přijímat zpětná volání.
      • Příklad: Komponenty implementované rozhraní IMixedRealityFocusHandler budou vyhledána pro GameObject získá nebo ztratí fokus.
      • Poznámka: Pokud se v aktuálním objektu GameObject nenajdou žádné komponenty odpovídající požadovanému rozhraní, bude Unity Event System prohledat nadřazený objekt GameObject.
  4. Pokud nejsou zaregistrované žádné obslužné rutiny globálního vstupu a nenajde se žádný objekt GameObject s odpovídající komponentou nebo rozhraním, vstupní systém zavolá každou obslužnou rutinu vstupu zaregistrovanou pro náhradní použití.

Příklad

Níže je příklad skriptu, který změní barvu připojeného vykreslovacího modulu, když ukazatel převezme nebo opustí fokus nebo když ukazatel vybere objekt.

public class ColorTap : MonoBehaviour, IMixedRealityFocusHandler, IMixedRealityPointerHandler
{
    private Color color_IdleState = Color.cyan;
    private Color color_OnHover = Color.white;
    private Color color_OnSelect = Color.blue;
    private Material material;

    private void Awake()
    {
        material = GetComponent<Renderer>().material;
    }

    void IMixedRealityFocusHandler.OnFocusEnter(FocusEventData eventData)
    {
        material.color = color_OnHover;
    }

    void IMixedRealityFocusHandler.OnFocusExit(FocusEventData eventData)
    {
        material.color = color_IdleState;
    }

    void IMixedRealityPointerHandler.OnPointerDown(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerDragged(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
    {
        material.color = color_OnSelect;
    }
}

Ukazatele dotazů

Je možné shromáždit všechny ukazatele, které jsou aktuálně aktivní, pomocí smyčky mezi dostupnými vstupními zdroji (tj. ovladači a dostupnými vstupy) a zjistit, které ukazatele jsou k nim připojeny.

var pointers = new HashSet<IMixedRealityPointer>();

// Find all valid pointers
foreach (var inputSource in CoreServices.InputSystem.DetectedInputSources)
{
    foreach (var pointer in inputSource.Pointers)
    {
        if (pointer.IsInteractionEnabled && !pointers.Contains(pointer))
        {
            pointers.Add(pointer);
        }
    }
}

Primární ukazatel

Vývojáři se mohou přihlásit k odběru FocusProviders PrimaryPointerChanged událostí být upozorněni, když se primární ukazatel v fokusu změnil. To může být velmi užitečné, pokud chcete zjistit, jestli uživatel právě komunikuje se scénou pohledem, paprskem ruky nebo jiným vstupním zdrojem.

private void OnEnable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.SubscribeToPrimaryPointerChanged(OnPrimaryPointerChanged, true);
}

private void OnPrimaryPointerChanged(IMixedRealityPointer oldPointer, IMixedRealityPointer newPointer)
{
    ...
}

private void OnDisable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.UnsubscribeFromPrimaryPointerChanged(OnPrimaryPointerChanged);

    // This flushes out the current primary pointer
    OnPrimaryPointerChanged(null, null);
}

Scéna PrimaryPointerExample (Assets/MRTK/Examples/Demos/Input/Scenes/PrimaryPointer) ukazuje, jak použít PrimaryPointerChangedHandler pro události k reakci na nový primární ukazatel.

Příklad primárního ukazatele

Výsledek ukazatele

Vlastnost ukazatele Result obsahuje aktuální výsledek pro dotaz scény použitý k určení objektu s fokusem. U ukazatele raycastu, jako jsou ty, které jsou ve výchozím nastavení vytvořeny pro ovladače pohybu, vstup pohledu a paprsky rukou, bude obsahovat umístění a normální stav raycastu.

private void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
{
    var result = eventData.Pointer.Result;
    var spawnPosition = result.Details.Point;
    var spawnRotation = Quaternion.LookRotation(result.Details.Normal);
    Instantiate(MyPrefab, spawnPosition, spawnRotation);
}

Scéna PointerResultExample (Assets/MRTK/Examples/Demos/Input/Scenes/PointerResult/PointerResultExample.unity) ukazuje, jak použít ukazatel Result k vytvoření objektu v umístění, kde byl nalezen.

Výsledek ukazatele

Zakázat ukazatele

Pokud chcete zapnout a zakázat ukazatele (například zakázat paprsek ruky), nastavte PointerBehavior pro daný typ ukazatele pomocí PointerUtils.

// Disable the hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff);

// Disable hand rays for the right hand only
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Right);

// Disable the gaze pointer
PointerUtils.SetGazePointerBehavior(PointerBehavior.AlwaysOff);

// Set the behavior to match HoloLens 1
// Note, if on HoloLens 2, you must configure your pointer profile to make the GGV pointer show up for articulated hands.
public void SetHoloLens1()
{
    PointerUtils.SetPokePointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGrabPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGGVBehavior(PointerBehavior.Default);
}

Další příklady najdete v tématu PointerUtils a TurnPointersOnOff .

Interakce s ukazateli prostřednictvím editoru

Pro události ukazatele zpracovávané nástrojem IMixedRealityPointerHandlerposkytuje MRTK další pohodlí ve formě PointerHandler komponenty, která umožňuje zpracování událostí ukazatele přímo prostřednictvím událostí Unity.

Obslužná rutina ukazatele

Rozsah ukazatele

Daleko ukazatele mají nastavení, která omezují, jak daleko budou provádět raycast a komunikovat s jinými objekty ve scéně. Ve výchozím nastavení je tato hodnota nastavená na 10 metrů. Tato hodnota byla zvolena tak, aby zůstala konzistentní s chováním prostředí HoloLens.

To lze změnit aktualizací DefaultControllerPointer polí komponenty prefab ShellHandRayPointer :

Rozsah ukazatele – určuje maximální vzdálenost, se kterou budou ukazatele interagovat.

Výchozí rozsah ukazatele – určuje délku paprsku nebo čáry ukazatele, který se vykreslí, když ukazatel s ničím nepracuje.

Viz také