Invoer van hoofd-blik en oog-blik in DirectX
Notitie
Dit artikel heeft betrekking op de verouderde systeemeigen WinRT-API's. Voor nieuwe systeemeigen app-projecten raden we u aan de OpenXR-API te gebruiken.
In Windows Mixed Reality wordt de blikinvoer van het oog en het hoofd gebruikt om te bepalen waar de gebruiker naar kijkt. U kunt de gegevens gebruiken om primaire invoermodellen aan te sturen, zoals head-staren en doorvoeren, en context te bieden voor verschillende interactietypen. Er zijn twee soorten gazevectoren beschikbaar via de API: hoofd-staren en oog-staren. Beide worden geleverd als een driedimensionale straal met een oorsprong en richting. Toepassingen kunnen vervolgens raycasten naar hun scènes of de echte wereld, en bepalen waarop de gebruiker zich richt.
Hoofd-blik vertegenwoordigt de richting waarin het hoofd van de gebruiker is gericht. U kunt head-staren zien als de positie en richting naar voren van het apparaat zelf, met de positie als het middelpunt tussen de twee beeldschermen. Hoofd-blik is beschikbaar op alle Mixed Reality apparaten.
Ogen staren vertegenwoordigt de richting waarnaar de ogen van de gebruiker kijken. De oorsprong bevindt zich tussen de ogen van de gebruiker. Het is beschikbaar op Mixed Reality apparaten met een oogtraceringssysteem.
Zowel hoofd- als oogstralen zijn toegankelijk via de SpatialPointerPose-API . Roep SpatialPointerPose::TryGetAtTimestamp aan om een nieuw SpatialPointerPose-object te ontvangen op het opgegeven tijdstempel- en coördinatensysteem. Deze SpatialPointerPose bevat een hoofd-blik oorsprong en richting. Het bevat ook een oog-blik oorsprong en richting als oogtracering beschikbaar is.
Ondersteuning voor apparaten
Functie | HoloLens (1e generatie) | HoloLens 2 | Immersive headsets |
Hoofd-blik | ✔️ | ✔️ | ✔️ |
Oog-blik | ❌ | ✔️ | ❌ |
Hoofd-blik gebruiken
Als u toegang wilt krijgen tot de head-gaze, 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 hoofd-blik. Dit wordt vertegenwoordigd door de variabele coördinaatSysteem in de volgende code. Ga voor meer informatie naar onze handleiding voor ontwikkelaars van coördinaatsystemen .
- Een tijdstempel die de exacte tijd van de aangevraagde hoofdhouding weergeeft. Normaal gesproken gebruikt u een tijdstempel die overeenkomt met het tijdstip waarop het huidige frame wordt weergegeven. U kunt deze voorspelde weergavetijdstempel ophalen uit 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 koppositie en voorwaartse richting toegankelijk als eigenschappen. De volgende code laat zien hoe u deze 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
}
Oog-blik gebruiken
Om ervoor te zorgen dat uw gebruikers oogbooginvoer kunnen gebruiken, moet elke gebruiker de eerste keer dat ze het apparaat gebruiken, een kalibratie voor ogentracering doornemen. De eye-gaze-API is vergelijkbaar met hoofd-staren. Het maakt gebruik van dezelfde SpatialPointerPose-API , die een ray-oorsprong en -richting biedt die u kunt raycasten op basis van uw scène. Het enige verschil is dat u oogtracering expliciet moet inschakelen voordat u deze kunt gebruiken:
- Vraag gebruikersmachtigingen aan om oogtracering in uw app te gebruiken.
- Schakel de mogelijkheid 'Gaze Input' in uw pakketmanifest in.
Toegang tot eye-gaze-invoer aanvragen
Wanneer uw app wordt opgestart, roept u EyesPose::RequestAccessAsync aan om toegang tot oogtracering aan te vragen. Het systeem vraagt de gebruiker indien nodig en retourneert GazeInputAccessStatus::Allowed zodra toegang is verleend. Dit is een asynchrone aanroep, dus er is wat extra beheer voor nodig. In het volgende voorbeeld wordt een losgekoppelde std::thread gepind 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 asynchrone aanroepen. U kunt ook de nieuwe co_await-functionaliteit gebruiken die wordt ondersteund door C++/WinRT. Hier volgt nog een voorbeeld voor het vragen van gebruikersmachtigingen:
- Met EyesPose::IsSupported() kan de toepassing het machtigingsdialoogvenster alleen activeren als er een oogtracering is.
- GazeInputAccessStatus m_gazeInputAccessStatus; Dit is om te voorkomen dat de machtigingsprompt steeds opnieuw wordt weergegeven.
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 gaze-invoermogelijkheid declareren
Dubbelklik in Solution Explorer op het bestand appxmanifest. Navigeer vervolgens naar de sectie Mogelijkheden en controleer de mogelijkheid Gaze-invoer .
Hiermee voegt u de volgende regels toe aan de sectie Pakket in het bestand appxmanifest:
<Capabilities>
<DeviceCapability Name="gazeInput" />
</Capabilities>
De oog-blikstraal krijgen
Zodra u toegang hebt gekregen tot ET, bent u vrij om de oog-blikstraal elk frame te pakken. Net als bij head-gaze, haalt u de SpatialPointerPose op door SpatialPointerPose::TryGetAtTimestamp aan te roepen met een gewenst tijdstempel- en coördinatensysteem. De SpatialPointerPose bevat een EyesPose-object via de eigenschap Eyes . Dit is alleen niet null als oogtracering is ingeschakeld. Van daaruit kunt u controleren of de gebruiker in het apparaat een oogtraceringskalibratie heeft door EyesPose::IsCalibrationValid aan te roepen. Gebruik vervolgens de eigenschap Gaze om de SpatialRay op te halen met de positie en richting van de ogen kijken. De eigenschap Gaze kan soms null zijn, dus controleer dit. Dit kan gebeuren als een gekalibreerde gebruiker tijdelijk de ogen sluit.
De volgende code laat zien hoe u toegang hebt tot de oog-star ray.
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 oogtracering niet beschikbaar is
Zoals vermeld in onze ontwerpdocumenten voor oogtracering, moeten zowel ontwerpers als ontwikkelaars op de hoogte zijn van gevallen waarin oogtraceringsgegevens mogelijk niet beschikbaar zijn.
Er zijn verschillende redenen waarom gegevens niet beschikbaar zijn:
- Een gebruiker die niet wordt gekalibreerd
- Een gebruiker heeft de app toegang geweigerd tot zijn/haar oogtraceringsgegevens
- Tijdelijke interferenties, zoals vlekken op het HoloLens-vizier of haar dat de ogen van de gebruiker omvat.
Hoewel sommige VAN de API's al in dit document zijn vermeld, geven we in het volgende een samenvatting van hoe u kunt detecteren dat oogtracering beschikbaar is als een beknopt overzicht:
Controleer of het systeem ondersteuning biedt voor oogtracering. Roep de volgende methode aan: Windows.Perception.Mensen. EyesPose.IsSupported()
Controleer of de gebruiker is gekalibreerd. Roep de volgende eigenschap aan: Windows.Perception.Mensen. EyesPose.IsCalibrationValid
Controleer of de gebruiker uw app toestemming heeft gegeven om hun oogtraceringsgegevens te gebruiken: Haal de huidige 'GazeInputAccessStatus' op. Een voorbeeld van hoe u dit doet, wordt uitgelegd in Toegang tot gaze-invoer aanvragen.
U kunt ook controleren of uw oogtraceringsgegevens niet verouderd zijn door een time-out toe te voegen tussen updates van ontvangen oogtraceringsgegevens en anderszins terugval naar hoofd staren, zoals hieronder wordt beschreven. Raadpleeg onze overwegingen voor terugvalontwerp voor meer informatie.
Blikken correleren met andere invoer
Soms merkt u dat u een SpatialPointerPose nodig hebt die overeenkomt met een gebeurtenis in het verleden. Als de gebruiker bijvoorbeeld een air tap uitvoert, wil uw app mogelijk weten waar ze naar keken. Voor dit doel zou het gebruik van SpatialPointerPose::TryGetAtTimestamp met de voorspelde frametijd onnauwkeurig zijn vanwege de latentie tussen de verwerking van systeeminvoer en de weergavetijd. Als u oog-staren gebruikt om te richten, hebben onze ogen de neiging om verder te gaan, zelfs voordat een doorvoeractie is uitgevoerd. Dit is minder een probleem voor een eenvoudige luchttik, 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 uit te voeren naar SpatialPointerPose::TryGetAtTimestamp, met behulp van een historisch tijdstempel dat overeenkomt met de invoergebeurtenis.
Voor invoer die via spatialinteractionManager wordt gerouteerd, is er echter een eenvoudigere methode. De SpatialInteractionSourceState heeft een eigen TryGetAtTimestamp-functie . Aanroepen die een perfect gecorreleerde SpatialPointerPose bieden zonder het gissen. Raadpleeg de documentatie handen en bewegingscontrollers in DirectX voor meer informatie over het werken met SpatialInteractionSourceStates.
Kalibratie
Voor een nauwkeurige werking van ogentracering moet elke gebruiker een gebruikerskalibratie voor oogtracering doorlopen. Hierdoor kan het apparaat het systeem aanpassen voor een comfortabelere en betere kijkervaring voor de gebruiker en tegelijkertijd nauwkeurige oogtracering garanderen. Ontwikkelaars hoeven niets te doen aan hun kant 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 afgemeld voor het kalibratieproces
- De laatste keer dat de gebruiker het apparaat gebruikte, is het kalibratieproces niet geslaagd
Ontwikkelaars moeten ervoor zorgen dat ze voldoende ondersteuning bieden voor gebruikers waarvoor oogtraceringsgegevens mogelijk niet beschikbaar zijn. Meer informatie over overwegingen voor terugvaloplossingen vindt u in Oogtracering op HoloLens 2.