Huvud- och ögonindata i DirectX

Anteckning

Den här artikeln handlar om äldre inbyggda WinRT-API:er. För nya interna appprojekt rekommenderar vi att du använder OpenXR-API:et.

I Windows Mixed Reality används indata från ögon och huvud för att avgöra vad användaren tittar på. Du kan använda data för att driva primära indatamodeller som head-gaze och commitoch tillhandahålla kontext för olika interaktionstyper. Det finns två typer av blickvektorer som är tillgängliga via API:et: head-gaze och eye-gaze. Båda tillhandahålls som en 3-dimensionell ray med ursprung och riktning. Program kan sedan gå in i bakgrunden, eller den verkliga världen, och avgöra vad användaren har som mål.

Huvudriktningen representerar den riktning som användarens huvud pekar på. Tänk på huvudriktningen som position och framåtriktning för själva enheten, med positionen som mittpunkten mellan de två skärmarna. Blicken är tillgänglig på alla Mixed Reality enheter.

Blicken representerar den riktning som användarens ögon tittar på. Ursprunget finns mellan användarens ögon. Den är tillgänglig på Mixed Reality enheter som innehåller ett ögonspårningssystem.

Både huvud- och ögonbilder är tillgängliga via API:et SpatialPointerPose. Anropa SpatialPointerPose::TryGetAtTimestamp för att ta emot ett nytt SpatialPointerPose-objekt vid den angivna tidsstämpeln och koordinatsystemet. Denna SpatialPointerPose innehåller ett huvudutsprung och riktning. Den innehåller också ett ögonperspektiv och riktning om ögonspårning är tillgängligt.

Stöd för enheter

Funktion HoloLens (första generationen) HoloLens 2 Integrerande headset
Blick mot huvudet ✔️ ✔️ ✔️
Blick ✔️

Använda head-gaze

Börja med att anropa SpatialPointerPose::TryGetAtTimestamp för att ta emot ett nytt SpatialPointerPose-objekt för att komma åt huvudet. Skicka följande parametrar.

  • Ett SpatialCoordinateSystem som representerar det koordinatsystem som du vill ha för huvudet. Detta representeras av variabeln coordinateSystem i följande kod. Mer information finns i utvecklarhandboken för koordinatsystem.
  • En tidsstämpel som representerar den exakta tiden för huvudställningen som begärdes. Normalt använder du en tidsstämpel som motsvarar den tid då den aktuella bildrutan visas. Du kan hämta den här förutsagda visningstidsstämpeln från ett HolographicFramePrediction-objekt som är tillgängligt via den aktuella HolographicFrame. Det här HolographicFramePrediction-objektet representeras av förutsägelsevariabeln i följande kod.

När du har en giltig SpatialPointerPose kan du komma åt huvudpositionen och framåtriktningen som egenskaper. Följande kod visar hur du kommer åt dem.

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
}

Använda ögonögon

För att användarna ska kunna använda blickindata måste varje användare gå igenom en ögonspårningsanvändare första gången de använder enheten. API:et för blicken liknar huvudögon. Den använder samma SpatialPointerPose-API, som tillhandahåller ett ursprung och en riktning för ray som du kan raycasta mot din scen. Den enda skillnaden är att du uttryckligen måste aktivera ögonspårning innan du använder den:

  1. Begär användarbehörighet för att använda ögonspårning i din app.
  2. Aktivera funktionen "Blickindata" i paketmanifestet.

Begära åtkomst till blickindata

När appen startas anropar du EyesPose::RequestAccessAsync för att begära åtkomst till ögonspårning. Systemet frågar användaren om det behövs och returnerar GazeInputAccessStatus::Tillåten när åtkomst har beviljats. Det här är ett asynkront anrop, så det kräver lite extra hantering. I följande exempel sätts en frånkopplad std::thread att vänta på resultatet, som den lagrar till en medlemsvariabel med namnet 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();

Att starta en frånkopplad tråd är bara ett alternativ för att hantera asynkrona anrop. Du kan också använda den nya co_await som stöds av C++/WinRT. Här är ett annat exempel för att be om användarbehörighet:

  • Med EyesPose::IsSupported() kan programmet endast utlösa behörighetsdialogrutan om det finns en ögonspårare.
  • GazeInputAccessStatus m_gazeInputAccessStatus; Det här är för att förhindra att behörighetsuppfrågas om och om igen.
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;    
        }
    });
}

Deklarera blickindata-funktionen

Dubbelklicka på filen appxmanifest i Solution Explorer. Gå sedan till avsnittet Funktioner och kontrollera funktionen Blickinmatning.

Kapacitet för blickindata

Detta lägger till följande rader i avsnittet Paket i filen appxmanifest:

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

Hämta ögonögonbilden

När du har fått åtkomst till ET kan du ta ögonbilden varje bildruta. Precis som med head-gaze kan du hämta SpatialPointerPose genom att anropa SpatialPointerPose::TryGetAtTimestamp med en önskad tidsstämpel och koordinatsystem. SpatialPointerPose innehåller ett EyesPose-objekt via egenskapen Eyes. Detta är endast icke-null om ögonspårning är aktiverat. Därifrån kan du kontrollera om användaren på enheten har en kalibrering av ögonspårning genom att anropa EyesPose::IsCalibrationValid. Använd sedan egenskapen Blick för att hämta spatialrayen som innehåller blickens position och riktning. Blickegenskapen kan ibland vara null, så se till att kontrollera detta. Detta kan inträffa om en kalibrerad användare tillfälligt stänger ögonen.

Följande kod visar hur du kommer åt ögonögonbilden.

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
        }
    }
}

Återställning när ögonspårning inte är tillgängligt

Som vi nämnde i våra dokument om ögonspårningsdesignbör både designers och utvecklare känna till instanser där spårningsdata för ögon inte är tillgängliga.

Det finns olika orsaker till att data inte är tillgängliga:

  • En användare kalibreras inte
  • En användare har nekat appen åtkomst till sina ögonspårningsdata
  • Tillfälliga interferenser, till exempel HoloLens på en HoloLens eller som gör att användarens ögon är i ockluderas.

Vissa AV API:erna har redan nämnts i det här dokumentet, men i följande dokument ger vi en sammanfattning av hur du identifierar att ögonspårning är tillgänglig som en snabbreferens:

Du kanske också vill kontrollera att dina ögonspårningsdata inte är inaktuella genom att lägga till en tidsgräns mellan mottagna uppdateringar av ögonspårningsdata och på annat sätt gå tillbaka till head-gaze enligt vad som beskrivs nedan.
Mer information finns i våra designöverväganden för återställning.


Korrelera blick med andra indata

Ibland kanske du upptäcker att du behöver en SpatialPointerPose som motsvarar en tidigare händelse. Om användaren till exempel använder en Air Tap kanske din app vill veta vad de tittar på. För detta ändamål skulle det vara felaktigt att bara använda SpatialPointerPose::TryGetAtTimestamp med den förväntade tidsramen på grund av svarstiden mellan systemets indatabearbetning och visningstid. Och om vi använder blicken för att rikta in oss på dem tenderar våra ögon att gå vidare även innan en genomföringsåtgärd avslutas. Det här är mindre problem för en enkel lufttryckning, men blir mer kritiskt när du kombinerar långa röstkommandon med snabba ögonförflyttningar. Ett sätt att hantera det här scenariot är att göra ytterligare ett anrop till SpatialPointerPose::TryGetAtTimestampmed hjälp av en historisk tidsstämpel som motsvarar indatahändelsen.

För indata som dirigeras genom SpatialInteractionManager finns det dock en enklare metod. SpatialInteractionSourceState har en egen TryGetAtTimestamp-funktion. Anrop som ger en perfekt korrelerad SpatialPointerPose utan gissning. Mer information om hur du arbetar med SpatialInteractionSourceStates finns i Hand- och rörelsekontroller i DirectX-dokumentationen.


Kalibrering

För att ögonspårningen ska fungera korrekt måste varje användare gå igenom en ögonspårningsanvändares kalibrering. Detta gör att enheten kan justera systemet för en mer bekväm och högkvalitativ visningsupplevelse för användaren och för att säkerställa korrekt ögonspårning på samma gång. Utvecklare behöver inte göra något på slutet för att hantera användaravsening. Systemet ser till att användaren uppmanas att kalibrera enheten under följande omständigheter:

  • Användaren använder enheten för första gången
  • Användaren valde tidigare bort kalibreringsprocessen
  • Kalibreringsprocessen lyckades inte den senaste gången användaren använde enheten

Utvecklare bör se till att tillhandahålla tillräckligt stöd för användare där ögonspårningsdata kanske inte är tillgängliga. Läs mer om överväganden för återställningslösningar i Ögonspårning på HoloLens 2.


Se även