Head-staring en ooginvoer in DirectX

Notitie

Dit artikel heeft betrekking op de verouderde, native WinRT-API's. Voor nieuwe native app-projecten raden we u aan de OpenXR API te gebruiken.

In Windows Mixed Reality wordt invoer van oog- en hoofd staren gebruikt om te bepalen wat de gebruiker bekijkt. U kunt de gegevens gebruiken om primaire invoermodellen te bevorderen, zoals starenen door te geven, en context te bieden voor verschillende interactietypen. Er zijn twee soorten staringsvectoren beschikbaar via de API: hoofd- en oogcontacten. Beide worden geleverd als een driedimensionale straal met een oorsprong en richting. Toepassingen kunnen vervolgens raycast in hun scènes of in de echte wereld maken en bepalen waarvoor de gebruiker zich richt.

Head-staring geeft de richting aan waarin het hoofd van de gebruiker wordt gewezen. U kunt head-staren zien als de positie en de voorwaartse richting van het apparaat zelf, met de positie als het middelpunt tussen de twee weergaven. Head-staring is beschikbaar op alle Mixed Reality apparaten.

Oogcontact geeft de richting aan waar de ogen van de gebruiker naar kijken. De oorsprong bevindt zich tussen de ogen van de gebruiker. Het is beschikbaar op Mixed Reality apparaten die een systeem voor het bijhouden van de ogen bevatten.

Zowel hoofd- als oogfoto's zijn toegankelijk via de SpatialPointerPose-API. Roep SpatialPointerPose::TryGetAtTimestamp aan om een nieuw SpatialPointerPose-object te ontvangen op het opgegeven tijdstempel en coördinaatsysteem. Deze SpatialPointerPose bevat een head-staren oorsprong en richting. Het bevat ook een oorsprong en richting van de oogcontacten als er oogtracking beschikbaar is.

Ondersteuning voor apparaten

Functie HoloLens (eerste generatie) HoloLens 2 Immersive headsets
Staren ✔️ ✔️ ✔️
Oogcontact ✔️

Head-staren gebruiken

Als u toegang wilt krijgen tot de head-staring, roept u eerst SpatialPointerPose::TryGetAtTimestamp aan om een nieuw SpatialPointerPose-object te ontvangen. Geef de volgende parameters door.

  • Een SpatialCoordinateSystem dat het coördinatensysteem vertegenwoordigt dat u wilt gebruiken voor de head-staring. Dit wordt vertegenwoordigd door de variabele coordinateSystem in de volgende code. Ga voor meer informatie naar onze ontwikkelaarshandleiding voor coördinatensystemen.
  • Een tijdstempel die de exacte tijd van de aangevraagde hoofdhouding vertegenwoordigt. Normaal gesproken gebruikt u een tijdstempel die overeenkomt met de tijd waarop het huidige frame wordt weergegeven. U kunt deze voorspelde weergavetijdstempel krijgen van een HolographicFramePrediction-object, dat toegankelijk is via het huidige HolographicFrame. Dit HolographicFramePrediction-object wordt vertegenwoordigd door de voorspellingsvariabele in de volgende code.

Zodra u een geldige SpatialPointerPose hebt, zijn de hoofdpositie en de voorwaartse richting toegankelijk als eigenschappen. De volgende code laat zien hoe u ze kunt openen.

using namespace winrt::Windows::UI::Input::Spatial;
using namespace winrt::Windows::Foundation::Numerics;

SpatialPointerPose pointerPose = SpatialPointerPose::TryGetAtTimestamp(coordinateSystem, prediction.Timestamp());
if (pointerPose)
{
   float3 headPosition = pointerPose.Head().Position();
   float3 headForwardDirection = pointerPose.Head().ForwardDirection();

   // Do something with the head-gaze
}

Oogcontact gebruiken

Om uw gebruikers ooginvoer te laten gebruiken, moet elke gebruiker de eerste keer dat ze het apparaat gebruiken, een oogtracking-gebruiker door het hoofd zien. De oogcontact-API is vergelijkbaar met head-staren. Deze maakt gebruik van dezelfde SpatialPointerPose-API, die een ray origin en -richting biedt die u kunt raycasten op uw scène. Het enige verschil is dat u oogtracking expliciet moet inschakelen voordat u deze kunt gebruiken:

  1. Vraag de gebruiker toestemming om oogtracking in uw app te gebruiken.
  2. Schakel de mogelijkheid 'Staren in uw pakketmanifest' in.

Toegang tot ooginvoer aanvragen

Wanneer uw app wordt geopend, roept u EyesPose::RequestAccessAsync aan om toegang tot het bijhouden van de ogen aan te vragen. Het systeem vraagt de gebruiker indien nodig en retourneert StaringInputAccessStatus::Toegestaan zodra toegang is verleend. Dit is een asynchrone aanroep, waardoor er wat extra beheer nodig is. In het volgende voorbeeld wordt een losgekoppelde std::thread aangemaakt om te wachten op het resultaat, dat wordt opgeslagen in een lidvariabele met de naam m_isEyeTrackingEnabled.

using namespace winrt::Windows::Perception::People;
using namespace winrt::Windows::UI::Input;

std::thread requestAccessThread([this]()
{
    auto status = EyesPose::RequestAccessAsync().get();

    if (status == GazeInputAccessStatus::Allowed)
        m_isEyeTrackingEnabled = true;
    else
        m_isEyeTrackingEnabled = false;
});

requestAccessThread.detach();

Het starten van een losgekoppelde thread is slechts één optie voor het afhandelen van asynsync-aanroepen. U kunt ook de nieuwe functionaliteit co_await door C++/WinRT wordt ondersteund. Hier is nog een voorbeeld van het vragen om gebruikersmachtiging:

  • Met EyesPose::IsSupported() kan de toepassing het machtigingsdialoogvenster alleen activeren als er een oogtracker is.
  • StarInputAccessStatus m_gazeInputAccessStatus; Dit is om te voorkomen dat de machtigingsprompt steeds opnieuw wordt gevraagd.
GazeInputAccessStatus m_gazeInputAccessStatus; // This is to prevent popping up the permission prompt over and over again.

// This will trigger to show the permission prompt to the user.
// Ask for access if there is a corresponding device and registry flag did not disable it.
if (Windows::Perception::People::EyesPose::IsSupported() &&
   (m_gazeInputAccessStatus == GazeInputAccessStatus::Unspecified))
{ 
    Concurrency::create_task(Windows::Perception::People::EyesPose::RequestAccessAsync()).then(
    [this](GazeInputAccessStatus status)
    {
        // GazeInputAccessStatus::{Allowed, DeniedBySystem, DeniedByUser, Unspecified}
            m_gazeInputAccessStatus = status;
        
        // Let's be sure to not ask again.
        if(status == GazeInputAccessStatus::Unspecified)
        {
                m_gazeInputAccessStatus = GazeInputAccessStatus::DeniedBySystem;    
        }
    });
}

De functie Staring Input declareren

Dubbelklik op het bestand appxmanifest in Solution Explorer. Navigeer vervolgens naar de sectie Mogelijkheden en controleer de mogelijkheid Stareninvoer.

Staren naar invoermogelijkheid

Hiermee worden de volgende regels toegevoegd aan de sectie Pakket in het bestand appxmanifest:

  <Capabilities>
    <DeviceCapability Name="gazeInput" />
  </Capabilities>

De oogcontactfoto krijgen

Zodra u toegang hebt gekregen tot ET, kunt u elk frame de oogcontactfoto pakken. Net als bij head-staren, kunt u SpatialPointerPose op halen door SpatialPointerPose::TryGetAtTimestamp aan te roepen met een gewenst tijdstempel en coördinaatsysteem. SpatialPointerPose bevat een EyesPose-object via de eigenschap Eyes. Dit is alleen niet null als oogtracking is ingeschakeld. Van hieruit kunt u controleren of de gebruiker op het apparaat een kalibratie voor oogtracking heeft door EyesPose::IsCalibrationValid aan te roepen. Gebruik vervolgens de eigenschap Staren om de SpatialRay op te halen die de positie en richting van de oogcontacten bevat. De eigenschap Staren kan soms null zijn, dus zorg ervoor dat u dit controleert. Dit kan gebeuren als een ge kalibreerde gebruiker tijdelijk de ogen sluit.

De volgende code laat zien hoe u toegang krijgt tot de oogfoto.

using namespace winrt::Windows::UI::Input::Spatial;
using namespace winrt::Windows::Foundation::Numerics;

SpatialPointerPose pointerPose = SpatialPointerPose::TryGetAtTimestamp(coordinateSystem, prediction.Timestamp());
if (pointerPose)
{
    if (pointerPose.Eyes() && pointerPose.Eyes().IsCalibrationValid())
    {
        if (pointerPose.Eyes().Gaze())
        {
            auto spatialRay = pointerPose.Eyes().Gaze().Value();
            float3 eyeGazeOrigin = spatialRay.Origin;
            float3 eyeGazeDirection = spatialRay.Direction;
            
            // Do something with the eye-gaze
        }
    }
}

Terugval wanneer oogtracking niet beschikbaar is

Zoals vermeld in onze ontwerp docsvoor oogtracking, moeten zowel ontwerpers als ontwikkelaars zich bewust zijn van instanties waar mogelijk geen gegevens voor het bijhouden van ogen beschikbaar zijn.

Er zijn verschillende redenen waarom gegevens niet beschikbaar zijn:

  • Een gebruiker die niet wordt ge kalibreerd
  • Een gebruiker heeft de app toegang geweigerd tot zijn/haar oogtrackinggegevens
  • Tijdelijke interferenties, zoals smudges op de HoloLens of haar die de ogen van de gebruiker insluiten.

Hoewel sommige VAN de API's al in dit document zijn genoemd, bieden we in het volgende een samenvatting van hoe u kunt detecteren dat oogtracking beschikbaar is als snelzoek:

U kunt ook controleren of uw oogtrackinggegevens niet zijn verouderd door een time-out toe te voegen tussen ontvangen gegevensupdates voor oogtracking en anderszins terugval naar hoofd staren, zoals hieronder wordt beschreven.
Ga naar onze overwegingen bij het terugvalontwerp voor meer informatie.


Staren correeren met andere invoer

Soms komt u erachter dat u een SpatialPointerPose nodig hebt die overeenkomt met een gebeurtenis in het verleden. Als de gebruiker bijvoorbeeld een tik in de lucht heeft, wil uw app mogelijk weten wat hij of zij heeft gekeken. Hiervoor is het eenvoudig gebruiken van SpatialPointerPose::TryGetAtTimestamp met de voorspelde frametijd onjuist vanwege de latentie tussen systeeminvoerverwerking en weergavetijd. En als we oogcontacten gebruiken voor targeting, gaan onze ogen vaak door, zelfs voordat we een door commit-actie afronden. Dit is minder een probleem voor een eenvoudige lucht tik, maar wordt belangrijker bij het combineren van lange spraakopdrachten met snelle oogbewegingen. Een manier om dit scenario af te handelen, is door een extra aanroep te doen naar SpatialPointerPose::TryGetAtTimestampmet behulp van een historische tijdstempel die overeenkomt met de invoergebeurtenis.

Voor invoer die door de SpatialInteractionManager routeert, is er echter een eenvoudigere methode. SpatialInteractionSourceState heeft een eigen TryGetAtTimestamp-functie. Aanroepen die een perfect gecorreleerd SpatialPointerPose bieden zonder het geraden. Zie de Documentatie over hands- en bewegingscontrollers in DirectX voor meer informatie over het werken met SpatialInteractionSourceStates.


Kalibratie

Als u wilt dat het bijhouden van de ogen correct werkt, moet elke gebruiker de kalibratie van een gebruiker bijhouden. Hierdoor kan het apparaat het systeem aanpassen voor een meer ervaring met het bekijken van een betere kwaliteit voor de gebruiker en tegelijkertijd nauwkeurige oogtracking garanderen. Ontwikkelaars hoeven niets aan hun kant te doen om de kalibratie van gebruikers te beheren. Het systeem zorgt ervoor dat de gebruiker onder de volgende omstandigheden wordt gevraagd het apparaat te kalibreren:

  • De gebruiker gebruikt het apparaat voor het eerst
  • De gebruiker heeft zich eerder voor het kalibratieproces uit gekozen
  • Het kalibratieproces is niet geslaagd de laatste keer dat de gebruiker het apparaat heeft gebruikt

Ontwikkelaars moeten ervoor zorgen dat ze voldoende ondersteuning bieden voor gebruikers waar mogelijk geen traceringsgegevens beschikbaar zijn. Meer informatie over overwegingen voor terugvaloplossingen in Oogtracking op HoloLens 2.


Zie ook