Aanwijzers — MRTK2
In dit artikel wordt uitgelegd hoe u aanwijzerinvoer in de praktijk configureert en erop reageert. Zie Aanwijzerarchitectuur voor meer informatie over het beheren van meerdere aanwijzers op hoog niveau.
Aanwijzers worden automatisch tijdens runtime weergegeven wanneer er een nieuwe controller wordt gedetecteerd. Er kan meer dan één aanwijzer worden gekoppeld aan een controller. Met het standaardprofiel voor aanwijzers krijgen Windows Mixed Reality controllers bijvoorbeeld zowel een lijn als een parabolische aanwijzer voor respectievelijk normale selectie en teleportatie.
Aanwijzerconfiguratie
Aanwijzers worden geconfigureerd als onderdeel van het invoersysteem in MRTK via een MixedRealityPointerProfile
. Dit type profiel wordt toegewezen aan een MixedRealityInputSystemProfile
in de MRTK-configuratiecontrole. Het aanwijzerprofiel bepaalt de cursor, de typen aanwijzers die tijdens runtime beschikbaar zijn en hoe deze aanwijzers met elkaar communiceren om te bepalen welke aanwijzer actief is.
Pointing Extent : definieert de maximale afstand waarvoor een aanwijzer kan communiceren met een GameObject.
Raycast-laagmaskers aanwijzen : dit is een matrix met laagmaskers met prioriteit om te bepalen met welke mogelijke GameObjects een bepaalde aanwijzer kan communiceren en de volgorde van interactie die moet worden geprobeerd. Dit kan handig zijn om ervoor te zorgen dat pointers eerst communiceren met UI-elementen vóór andere scèneobjecten.
Configuratie van aanwijzeropties
De standaardconfiguratie mrtk-aanwijzerprofiel bevat de volgende aanwijzerklassen en bijbehorende kant-en-klare prefabs. De lijst met aanwijzers die tijdens runtime beschikbaar zijn voor het systeem, wordt gedefinieerd onder Aanwijzeropties in het aanwijzerprofiel. Ontwikkelaars kunnen deze lijst gebruiken om bestaande aanwijzers opnieuw te configureren, nieuwe aanwijzers toe te voegen of een aanwijzer te verwijderen.
Elke aanwijzervermelding wordt gedefinieerd door de volgende set gegevens:
Controllertype : de set controllers waarvoor een aanwijzer geldig is.
- De PokePointer is bijvoorbeeld verantwoordelijk voor het 'pokken' van objecten met een vinger en is standaard gemarkeerd als ondersteuning voor het type gelede handcontroller. Aanwijzers worden alleen geïnstantieerd wanneer er een controller beschikbaar komt en met name het controllertype bepaalt met welke controllers deze pointer-prefab kan worden gemaakt.
Handigheid : maakt het mogelijk dat een aanwijzer alleen wordt geïnstantieerd voor een specifieke hand (links/rechts)
Notitie
Als u de eigenschap Handigheid van een aanwijzer instelt op Geen , wordt deze effectief uitgeschakeld uit het systeem als alternatief voor het verwijderen van die aanwijzer uit de lijst.
- Pointer Prefab : deze prefab-asset wordt geïnstantieerd wanneer een controller die overeenkomt met het opgegeven controllertype en de handbaarheid wordt bijgehouden.
Het is mogelijk om meerdere aanwijzers te koppelen aan een controller. In (Assets/MRTK/SDK/Profiles/HoloLens2/) is de gelede handcontroller bijvoorbeeld DefaultHoloLens2InputSystemProfile
gekoppeld aan de PokePointer, GrabPointer en de DefaultControllerPointer (handstralen).
Notitie
MRTK biedt een set prefabs voor aanwijzers in Assets/MRTK/SDK/Features/UX/Prefabs/Pointers. Er kan een nieuwe aangepaste prefab worden gemaakt zolang deze een van de aanwijzerscripts bevat in Assets/MRTK/SDK/Features/UX/Scripts/Pointers of een ander script dat wordt geïmplementeerd IMixedRealityPointer
.
Cursorconfiguratie
De Gaze-cursor kan rechtstreeks worden geconfigureerd via de GazeCursorPrefab
eigenschap in de MixedRealityInputSystemProfile
editor. Als u de cursor wilt configureren die wordt gebruikt voor andere aanwijzers, moet u de prefab wijzigen die wordt gebruikt in het CursorPrefab
veld van de bijbehorende BaseControllerPointer
. Als u de cursor programmatisch wilt wijzigen, wijzigt u de BaseCursor
eigenschap voor het bijbehorende IMixedRealityPointer
gedrag.
Zie onze cursor-prefabs in Assets/MRTK/SDK/Features/UX/Prefabs/Cursors voor voorbeelden van implementaties van cursorgedrag. Met name de DefaultGazeCursor biedt een robuuste implementatie van het wijzigen van de afbeelding van de cursor op basis van contextuele status.
Standaardklassen voor aanwijzers
De volgende klassen zijn de out-of-box MRTK-aanwijzers die beschikbaar zijn en die zijn gedefinieerd in het standaard MRTK-aanwijzerprofiel dat hierboven wordt beschreven. Elke pointer-prefab die wordt geleverd onder Assets/MRTK/SDK/Features/UX/Prefabs/Pointers bevat een van de gekoppelde aanwijzeronderdelen.
Verre aanwijzers
LinePointer
LinePointer, een basisaanwijzerklasse, tekent een lijn van de bron van de invoer (d.w.w. de controller) in de aanwijzerrichting en ondersteunt één straal die in deze richting wordt gegoten. Over het algemeen worden onderliggende klassen zoals de ShellHandRayPointer
en de teleportpointers geïnstantieerd en gebruikt (die ook lijnen tekenen om aan te geven waar teleportatie eindigt) in plaats van deze klasse die voornamelijk algemene functionaliteit biedt.
Voor bewegingscontrollers zoals in Oculus, Vive en Windows Mixed Reality komt de rotatie overeen met de rotatie van de controller. Voor andere controllers, zoals HoloLens 2 gelede handen, komt de rotatie overeen met de door het systeem opgegeven aanwijspositie van de hand.
CurvePointer
CurvePointer breidt de LinePointer-klasse uit door het mogelijk maken van straalzweiningen met meerdere stappen langs een curve. Deze basispointerklasse is handig voor gekromde exemplaren, zoals teleportatiepunten, waarbij de lijn consistent buigt in een parabool.
ShellHandRayPointer
De implementatie van ShellHandRayPointer, die zich uitstrekt van LinePointer
, wordt gebruikt als de standaardinstelling voor het MRTK-aanwijzerprofiel. De prefab DefaultControllerPointer implementeert de ShellHandRayPointer
klasse.
GGVPointer
De GGVPointer, ook wel bekend als de GGV-aanwijzer (Gaze/Gesture/Voice), maakt holoLens 1-stijl en tikinteracties mogelijk, voornamelijk via staren en lucht tikken of staren en stem selecteren interactie. De positie en richting van de GGV-aanwijzer worden aangestuurd door de positie en draaiing van het hoofd.
TouchPointer
De TouchPointer is verantwoordelijk voor het werken met Unity Touch-invoer (bijvoorbeeld touchscreen). Dit zijn 'verre interacties' omdat de handeling van het aanraken van het scherm een straal van de camera naar een potentieel verre locatie in de scène werpt.
MousePointer
De MousePointer maakt een scherm mogelijk voor raycast voor verre interacties, maar voor muis in plaats van aanraking.
Notitie
Muisondersteuning is niet standaard beschikbaar in MRTK, maar kan worden ingeschakeld door een nieuwe invoergegevensprovider van het type MouseDeviceManager
toe te voegen aan het MRTK-invoerprofiel en de MixedRealityMouseInputProfile
toe te wijzen aan de gegevensprovider.
Aanwijzers in de buurt
PokePointer
De PokePointer wordt gebruikt om te communiceren met gameobjecten die ondersteuning bieden voor 'bijna-interactie aanraakbaar'. Dit zijn GameObjects met een gekoppeld NearInteractionTouchable
script. In het geval van UnityUI zoekt deze aanwijzer naar NearInteractionTouchableUnityUIs. De PokePointer maakt gebruik van een SphereCast om het dichtstbijzijnde aanraakbare element te bepalen en wordt gebruikt om dingen zoals de drukbare knoppen aan te zetten.
Wanneer u het GameObject configureert met het NearInteractionTouchable
onderdeel, moet u ervoor zorgen dat u de parameter localForward configureert om naar de voorkant van de knop of een ander object te wijzen dat aanraakbaar moet worden gemaakt. Zorg er ook voor dat de grenzen van het aanraakbare object overeenkomen met de grenzen van het aanraakbare object.
Nuttige eigenschappen van de aanwijzer:
- TouchableDistance: maximale afstand waarbinnen een aanraakbaar oppervlak kan worden gebruikt
- Visuals: Game-object dat wordt gebruikt om een vingertipvisual weer te geven (standaard de ring op vinger).
- Lijn: optionele lijn om van de vingertop naar het actieve invoeroppervlak te tekenen.
- Poke Layer Masks : een matrix met laagmaskers met prioriteit om te bepalen met welke mogelijke GameObjects de aanwijzer kan communiceren en de volgorde van interactie die moet worden geprobeerd. Houd er rekening mee dat een GameObject ook een
NearInteractionTouchable
onderdeel moet hebben om te communiceren met een aanwijzer.
SpherePointer
De SpherePointer gebruikt UnityEngine.Physics.OverlapSphere om het dichtstbijzijnde NearInteractionGrabbable
object voor interactie te identificeren, wat handig is voor 'grabbable' invoer, zoals de ManipulationHandler
. Net als bij het PokePointer
/NearInteractionTouchable
functionele paar moet het gameobject een onderdeel bevatten dat het NearInteractionGrabbable
script is om interactie te hebben met de Sphere Pointer.
Nuttige spherepointer-eigenschappen:
- Sphere Cast Radius: de straal voor de bol die wordt gebruikt om te zoeken naar grijpbare objecten.
- Near Object Margin: de afstand boven op de Sphere Cast Radius om te detecteren of een object zich in de buurt van de aanwijzer bevindt. Totale radius voor detectie van near object is Sphere Cast Radius + Near Object Margin
- Hoek van objectsector: de hoek rond de voorwaartse as van de aanwijzer voor het uitvoeren van query's op objecten in de buurt. Maakt de
IsNearObject
queryfunctie als een kegel. Dit is standaard ingesteld op 66 graden om overeen te komen met hololens 2-gedrag
- Near Object Smoothing Factor: Smoothing Factor voor detectie van bijna-object. Als een object wordt gedetecteerd in de radius van het nabije object, wordt de opgevraagde straal vervolgens Near Object Radius * (1 + Near Object Smoothing Factor) om de gevoeligheid te verminderen en het moeilijker te maken voor een object om het detectiebereik te verlaten.
- Grab Layer Masks : een matrix met layermasks met prioriteit om te bepalen met welke mogelijke GameObjects de aanwijzer kan werken en welke volgorde van interactie moet worden uitgevoerd. Houd er rekening mee dat een GameObject ook een
NearInteractionGrabbable
moet hebben om te communiceren met een SpherePointer.Notitie
De laag Ruimtelijk bewustzijn is uitgeschakeld in de standaard prefab grabpointer die door MRTK wordt geleverd. Dit wordt gedaan om de prestatie-impact van het uitvoeren van een sphere overlapquery met de ruimtelijke mesh te verminderen. U kunt dit inschakelen door de prefab van GrabPointer te wijzigen.
- Colliders negeren Niet in FOV : of colliers die zich mogelijk in de buurt van de aanwijzer bevinden, maar niet daadwerkelijk in de visuele FOV moeten worden genegeerd. Dit kan onbedoelde grijpingen voorkomen en zorgt ervoor dat handstralen worden ingeschakeld wanneer u in de buurt van een grijpbare bent, maar deze niet kunt zien. De visual-FOV wordt om prestatieredenen gedefinieerd via een kegel in plaats van het typische frustum. Deze kegel is gecentreerd en georiënteerd hetzelfde als het frustum van de camera met een straal die gelijk is aan de halve beeldschermhoogte (of verticale FOV).
Teleport-aanwijzers
TeleportPointer
zal een teleportaanvraag indienen wanneer actie wordt ondernomen (dat wil dat de teleportknop wordt ingedrukt) om de gebruiker te verplaatsen.ParabolicTeleportPointer
zal een teleportaanvraag indienen wanneer actie wordt ondernomen (dat wil dat de teleportknop wordt ingedrukt) met een parabolische lijn raycast om de gebruiker te verplaatsen.
Ondersteuning voor aanwijzer voor mixed reality-platforms
De volgende tabel bevat informatie over de aanwijzertypen die doorgaans worden gebruikt voor de algemene platforms in MRTK. OPMERKING: het is mogelijk om verschillende typen aanwijzers toe te voegen aan deze platforms. U kunt bijvoorbeeld een Poke-aanwijzer of Sphere-aanwijzer toevoegen aan VR. Daarnaast kunnen VR-apparaten met een gamepad gebruikmaken van de GGV-aanwijzer.
Aanwijzer | OpenVR | Windows Mixed Reality | HoloLens 1 | HoloLens 2 |
---|---|---|---|---|
ShellHandRayPointer | Geldig | Geldig | Geldig | |
TeleportPointer | Geldig | Geldig | ||
GGVPointer | Geldig | |||
SpherePointer | Geldig | |||
PokePointer | Geldig |
Aanwijzerinteracties via code
Aanwijzer-gebeurtenisinterfaces
MonoBehaviours die een of meer van de volgende interfaces implementeren en zijn toegewezen aan een GameObject met een Collider
, ontvangen aanwijzerinteractiegebeurtenissen zoals gedefinieerd door de bijbehorende interface.
Gebeurtenis | Beschrijving | Handler |
---|---|---|
Voordat de focus is gewijzigd/de focus is gewijzigd | Verhoogd op zowel het spelobject dat de focus verliest als degene die het krijgt elke keer dat een aanwijzer de focus verandert. | IMixedRealityFocusChangedHandler |
Focus invoeren/afsluiten | Verhoogd op het spelobject dat de focus krijgt wanneer de eerste aanwijzer het binnenkomt en op degene die de focus verliest wanneer de laatste aanwijzer deze verlaat. | IMixedRealityFocusHandler |
Aanwijzer omlaag/gesleept/omhoog/geklikt | Opgeheven om aanwijzer te drukken, slepen en los te laten. | IMixedRealityPointerHandler |
Aanraken gestart/bijgewerkt/voltooid | Gegenereerd door aanraakgevoelige aanwijzers, zoals PokePointer om aanraakactiviteit te rapporteren. |
IMixedRealityTouchHandler |
Notitie
IMixedRealityFocusChangedHandler
en IMixedRealityFocusHandler
moeten worden verwerkt in de objecten waarop ze zijn verheven. Het is mogelijk om focusgebeurtenissen globaal te ontvangen, maar in tegenstelling tot andere invoergebeurtenissen blokkeert globale gebeurtenis-handler het ontvangen van gebeurtenissen niet op basis van de focus (de gebeurtenis wordt ontvangen door zowel de globale handler als een bijbehorend object in focus).
Aanwijzerinvoer gebeurtenissen in actie
Aanwijzerinvoergebeurtenissen worden op dezelfde manier herkend en verwerkt door het MRTK-invoersysteem als gewone invoergebeurtenissen. Het verschil is dat aanwijzerinvoergebeurtenissen alleen worden verwerkt door het GameObject in focus door de aanwijzer die de invoergebeurtenis heeft geactiveerd, evenals eventuele globale invoerhandlers. Normale invoergebeurtenissen worden verwerkt door GameObjects met de focus voor alle actieve aanwijzers.
- Het MRTK-invoersysteem herkent dat er een invoergebeurtenis heeft plaatsgevonden
- Het MRTK-invoersysteem schakelt de relevante interfacefunctie voor de invoer-gebeurtenis naar alle geregistreerde globale invoerhandlers
- Het invoersysteem bepaalt welk GameObject de focus heeft voor de aanwijzer die de gebeurtenis heeft geactiveerd
- Het invoersysteem maakt gebruik van het Event System van Unity om de relevante interfacefunctie voor alle overeenkomende onderdelen op het gameobject te activeren
- Als op enig moment een invoergebeurtenis is gemarkeerd als gebruikt, wordt het proces beëindigd en ontvangen geen verdere GameObjects callbacks.
- Voorbeeld: Onderdelen die de interface
IMixedRealityFocusHandler
implementeren, worden gezocht naar een GameObject dat de focus verkrijgt of verliest - Opmerking: Het Unity Event System zal opbellen om het bovenliggende GameObject te doorzoeken als er geen onderdelen zijn gevonden die overeenkomen met de gewenste interface op het huidige GameObject.
- Voorbeeld: Onderdelen die de interface
- Als er geen globale invoerhandlers zijn geregistreerd en er geen GameObject wordt gevonden met een overeenkomend onderdeel/interface, roept het invoersysteem elke geregistreerde invoerhandler aan
Voorbeeld
Hieronder ziet u een voorbeeldscript waarmee de kleur van de gekoppelde renderer wordt gewijzigd wanneer een aanwijzer de focus neemt of verlaat of wanneer een aanwijzer het object selecteert.
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;
}
}
Querypointers
Het is mogelijk om alle aanwijzers die momenteel actief zijn, te verzamelen door de beschikbare invoerbronnen (bijvoorbeeld controllers en invoer) te doorlopen om te ontdekken welke aanwijzers zijn gekoppeld.
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);
}
}
}
Primaire aanwijzer
Ontwikkelaars kunnen zich abonneren op de gebeurtenis FocusProviders PrimaryPointerChanged om een melding te ontvangen wanneer de primaire aanwijzer in focus is gewijzigd. Dit kan zeer nuttig zijn om te bepalen of de gebruiker momenteel interactie heeft met een scène via staren of een handstraal of een andere invoerbron.
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);
}
De PrimaryPointerExample
scène (Assets/MRTK/Examples/Demos/Input/Scenes/PrimaryPointer) laat zien hoe u de PrimaryPointerChangedHandler
gebruikt voor gebeurtenissen om te reageren op een nieuwe primaire aanwijzer.
Aanwijzerresultaat
De eigenschap pointer Result
bevat het huidige resultaat voor de scènequery die wordt gebruikt om het object met de focus te bepalen. Voor een raycast-aanwijzer, zoals de aanwijzer die standaard is gemaakt voor bewegingscontrollers, staarinvoer en handstralen, bevat deze de locatie en het normale van de raycast-hit.
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);
}
De PointerResultExample
scène (Assets/MRTK/Examples/Demos/Input/Scenes/PointerResult/PointerResultExample.unity) laat zien hoe u de aanwijzer Result
gebruikt om een object op de trefferlocatie te genereren.
Aanwijzers uitschakelen
Als u aanwijzers wilt in- en uitschakelen (bijvoorbeeld om de handstraal uit te schakelen), stelt u de PointerBehavior
in voor een bepaald type aanwijzer via 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);
}
Zie PointerUtils
en TurnPointersOnOff
voor meer voorbeelden.
Aanwijzerinteracties via editor
Voor aanwijzergebeurtenissen die worden verwerkt door IMixedRealityPointerHandler
, biedt MRTK nog meer gemak in de vorm van het PointerHandler
onderdeel, waardoor aanwijzergebeurtenissen rechtstreeks via Unity-gebeurtenissen kunnen worden verwerkt.
Aanwijzer-bereik
Verre aanwijzers hebben instellingen waarmee wordt beperkt hoe ver ze raycasten en interactie hebben met andere objecten in de scène. Deze waarde is standaard ingesteld op 10 meter. Deze waarde is gekozen om consistent te blijven met het gedrag van de HoloLens-shell.
Dit kan worden gewijzigd door de velden van ShellHandRayPointer
het DefaultControllerPointer
prefab-onderdeel bij te werken:
Aanwijzer-bereik : hiermee bepaalt u de maximale afstand waarmee aanwijzers werken.
Default Pointer Extent : hiermee bepaalt u de lengte van de aanwijzerstraal/-lijn die wordt weergegeven wanneer de aanwijzer nergens interactie mee heeft.