Inmatning av huvud och blick 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 huvud blick och incheckning och ge kontext för olika interaktionstyper. Det finns två typer av blickvektorer som är tillgängliga via API:et: huvud-blick och blick. Båda tillhandahålls som en tredimensionell stråle med ursprung och riktning. Program kan sedan strålkasta in i sina scener, eller den verkliga världen, och avgöra vad användaren riktar in sig på.

Huvud-blick representerar den riktning som användarens huvud pekas i. Tänk på huvud blicken som enhetens position och framåtriktning, med positionen som mittpunkt mellan de två skärmarna. Blicken är tillgänglig på alla Mixed Reality enheter.

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

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

Stöd för enheter

Funktionen HoloLens (första generationen) HoloLens 2 Integrerande headset
Huvud-blick ✔️ ✔️ ✔️
Blick ✔️

Använda huvud-blick

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

  • Ett SpatialCoordinateSystem som representerar det koordinatsystem som du vill ha för huvud blicken. Detta representeras av variabeln coordinateSystem i följande kod. Mer information finns i vår utvecklarguide för koordinatsystem .
  • En tidsstämpel som representerar den exakta tiden för den begärda huvudställningen. Normalt använder du en tidsstämpel som motsvarar den tid då den aktuella ramen 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 är huvudpositionen och framåtriktningen tillgängliga 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 blick

För att användarna ska kunna använda blickinmatning måste varje användare gå igenom en ögonspårningsanvändares kalibrering första gången de använder enheten. API:et för ögonöga liknar huvudöga. Den använder samma SpatialPointerPose-API , som ger ett ray-ursprung och en riktning som du kan strålkasta mot din scen. Den enda skillnaden är att du uttryckligen måste aktivera ögonspårning innan du använder det:

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

Begära åtkomst till ögonögaindata

När appen startas anropar du EyesPose::RequestAccessAsync för att begära åtkomst till ögonspårning. Systemet uppmanar användaren om det behövs och returnerar GazeInputAccessStatus::Allowed när åtkomsten har beviljats. Det här är ett asynkront anrop, så det kräver lite extra hantering. I följande exempel startar en frånkopplad std::thread för att vänta på resultatet, som lagras i 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 de nya co_await funktioner som stöds av C++/WinRT. Här är ett annat exempel för att be om användarbehörighet:

  • EyesPose::IsSupported() tillåter att programmet bara utlöser behörighetsdialogrutan om det finns en ögonspårare.
  • GazeInputAccessStatus m_gazeInputAccessStatus; Detta för att förhindra att behörighetsprompten dyker upp 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 funktionen Gaze Input

Dubbelklicka på appxmanifest-filen i Solution Explorer. Gå sedan till avsnittet Funktioner och kontrollera funktionen Gaze Input (Blickindata ).

Kapacitet för blickinmatning

Följande rader läggs till i avsnittet Paket i filen appxmanifest:

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

Få blickstrålen

När du har fått tillgång till ET kan du ta tag i ögonögastrålen varje bildruta. Precis som med blicken hämtar du SpatialPointerPose genom att anropa SpatialPointerPose::TryGetAtTimestamp med en önskad tidsstämpel och ett koordinatsystem. SpatialPointerPose innehåller ett EyesPose-objekt via egenskapen Ögon . Detta är endast icke-null om ögonspårning är aktiverat. Därifrån kan du kontrollera om användaren på enheten har en ögonspårningskalibrering genom att anropa EyesPose::IsCalibrationValid. Använd sedan egenskapen Gaze för att hämta SpatialRay som innehåller blickens position och riktning. Egenskapen Gaze 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ögastrålen.

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ämnt i våra dokument för ögonspårningsdesign bör både designers och utvecklare vara medvetna om instanser där ögonspårningsdata kanske inte är tillgängliga.

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

  • En användare som inte kalibreras
  • En användare har nekat appen åtkomst till sina ögonspårningsdata
  • Tillfälliga störningar, till exempel fläckar på HoloLens-visorn eller hår som ocksuderar användarens ögon.

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

Du kanske också vill kontrollera att dina ögonspårningsdata inte är inaktuella genom att lägga till en timeout mellan mottagna uppdateringar av ögonspårningsdata och annars återställning till huvudöga enligt beskrivningen nedan. Besök våra designöverväganden för återställning för mer information.


Korrelera blicken med andra indata

Ibland kanske du upptäcker att du behöver en SpatialPointerPose som motsvarar en händelse tidigare. Om användaren till exempel gör en air tap kanske din app vill veta vad de tittade på. För det här ändamålet 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. Dessutom, om du använder blicken för att rikta in dig, tenderar våra ögon att gå vidare även innan de slutför en incheckningsåtgärd. Detta är mindre av ett problem för en enkel Air Tap, men blir mer kritisk när du kombinerar långa röstkommandon med snabba ögonrörelser. Ett sätt att hantera det här scenariot är att göra ytterligare ett anrop till SpatialPointerPose::TryGetAtTimestamp med hjälp av en historisk tidsstämpel som motsvarar indatahändelsen.

Men för indata som dirigerar genom SpatialInteractionManager finns det 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örelsekontrollanter i DirectX-dokumentationen .


Kalibrering

För att ögonspårning 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 bekvämare och mer 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å sin sida för att hantera användarkalibrering. 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 har tidigare avanmält sig från 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 reservlösningar på Eye tracking on HoloLens 2.


Se även