XR_EXT_spatial_anchor
Name String
XR_EXT_spatial_anchor
Extension Type
Instance extension
Registered Extension Number
763
Revision
1
Ratification Status
Ratified
Extension and Version Dependencies
XR_EXT_spatial_entity
Contributors
Nihav Jain, Google
Natalie Fleury, Meta
Yuichi Taguchi, Meta
Ron Bessems, Meta
Yin Li, Microsoft
Jimmy Alamparambil, ByteDance
Zhipeng Liu, ByteDance
Jun Yan, ByteDance
Przegląd
To rozszerzenie bazuje na XR_EXT_spatial_entity i umożliwia aplikacjom tworzenie kotwic przestrzennych, czyli dowolnych punktów w fizycznym otoczeniu użytkownika, które będą śledzone przez środowisko wykonawcze. Środowisko wykonawcze powinno w razie potrzeby dostosowywać pozycję i orientację początku kotwicy w czasie, niezależnie od innych przestrzeni i kotwic, aby zachować jej pierwotne mapowanie do świata rzeczywistego.
Kotwica, która śledzi daną pozycję i orientację w XrSpatialContextEXT, jest reprezentowana jako element przestrzenny z komponentem XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT.
Zalety korzystania z kotwic
W miarę jak środowisko wykonawcze aktualizuje informacje o fizycznym otoczeniu użytkownika w trakcie działania XrSpatialContextEXT, obiekty wirtualne mogą się przesuwać względem miejsca, w którym zostały umieszczone przez aplikację, co wpływa na realizm aplikacji i jakość wrażeń użytkownika. Tworząc kotwicę w pobliżu miejsca, w którym umieszczony jest obiekt wirtualny, a następnie renderując ten obiekt wirtualny względem jego kotwicy, aplikacja może zapewnić, że każdy obiekt wirtualny będzie znajdował się w tej samej pozycji i orientacji w środowisku fizycznym. W przeciwieństwie do niektórych przestrzeni odniesienia kotwice nie są też narażone na ponowne wyśrodkowanie na poziomie systemu.
Obsługa środowiska wykonawczego
Jeśli środowisko wykonawcze obsługuje kotwice przestrzenne, musi to wskazać, wymieniając XR_SPATIAL_CAPABILITY_ANCHOR_EXT w xrEnumerateSpatialCapabilitiesEXT .
Konfiguracja
Struktura XrSpatialCapabilityConfigurationAnchorEXT jest zdefiniowana w ten sposób:
typedef struct XrSpatialCapabilityConfigurationAnchorEXT {
XrStructureType type;
const void* next;
XrSpatialCapabilityEXT capability;
uint32_t enabledComponentCount;
const XrSpatialComponentTypeEXT* enabledComponents;
} XrSpatialCapabilityConfigurationAnchorEXT;
Opisy elementów
typeto XrStructureType tej struktury.nexttoNULLlub wskaźnik do następnej struktury w łańcuchu struktur.capabilityto XrSpatialCapabilityEXT .enabledComponentCounttouint32_topisujący liczbę elementów w tablicyenabledComponents.enabledComponentsto wskaźnik do tablicy XrSpatialComponentTypeEXT .
Aplikacje mogą włączyć funkcję przestrzenną XR_SPATIAL_CAPABILITY_ANCHOR_EXT, dodając wskaźnik do struktury XrSpatialCapabilityConfigurationAnchorEXT w XrSpatialContextCreateInfoEXT :: capabilityConfigs .
Jeśli capability nie jest XR_SPATIAL_CAPABILITY_ANCHOR_EXT, środowisko wykonawcze musi zwrócić XR_ERROR_VALIDATION_FAILURE .
Prawidłowe użycie (pośrednie)
- Przed użyciem XrSpatialCapabilityConfigurationAnchorEXT musi być włączone rozszerzenie
XR_EXT_spatial_anchor. -
typemusi mieć wartośćXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT -
nextmusi mieć wartośćNULLlub prawidłowy wskaźnik do następnej struktury w łańcuchu struktur. -
capabilitymusi być prawidłową wartością XrSpatialCapabilityEXT. -
enabledComponentsmusi być wskaźnikiem do tablicyenabledComponentCountprawidłowych wartości XrSpatialComponentTypeEXT. - Parametr
enabledComponentCountmusi być większy niż0.
Gwarantowane komponenty
Środowisko wykonawcze, które obsługuje XR_SPATIAL_CAPABILITY_ANCHOR_EXT musi udostępniać te komponenty przestrzenne jako gwarantowane komponenty wszystkich elementów utworzonych lub wykrytych przez tę funkcję i musi je wymieniać w xrEnumerateSpatialCapabilityComponentTypesEXT :
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
Komponent kotwicy
Dane komponentu
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT używa XrPosef do przechowywania danych, które określają pozycję i orientację kotwicy.
Struktura listy komponentów do wysyłania zapytań o dane
Struktura XrSpatialComponentAnchorListEXT jest zdefiniowana w ten sposób:
typedef struct XrSpatialComponentAnchorListEXT {
XrStructureType type;
void* next;
uint32_t locationCount;
XrPosef* locations;
} XrSpatialComponentAnchorListEXT;
Opisy elementów
typeto XrStructureType tej struktury.nexttoNULLlub wskaźnik do następnej struktury w łańcuchu struktur.locationCounttouint32_topisujący liczbę elementów w tablicylocations.locationsto tablica XrPosef .
Jeśli XrSpatialComponentAnchorListEXT znajduje się w łańcuchu XrSpatialComponentDataQueryResultEXT :: next, ale XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT nie jest uwzględniony w XrSpatialComponentDataQueryConditionEXT :: componentTypes, środowisko wykonawcze musi zwrócić XR_ERROR_VALIDATION_FAILURE z xrQuerySpatialComponentDataEXT .
Jeśli locationCount jest mniejsza niż XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput, środowisko wykonawcze musi zwrócić XR_ERROR_SIZE_INSUFFICIENT z xrQuerySpatialComponentDataEXT .
Prawidłowe użycie (pośrednie)
- Przed użyciem XrSpatialComponentAnchorListEXT musi być włączone rozszerzenie
XR_EXT_spatial_anchor -
typemusi mieć wartośćXR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT -
nextmusi mieć wartośćNULLlub prawidłowy wskaźnik do następnej struktury w łańcuchu struktur. -
locationsmusi być wskaźnikiem do tablicylocationCountstruktur XrPosef. - Parametr
locationCountmusi być większy niż0
Konfiguracja
Jeśli XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT jest wymieniony w XrSpatialCapabilityComponentTypesEXT :: componentTypes dla jakiejś funkcji, aplikacja może go włączyć, dodając wyliczenie do listy XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents w strukturze pochodnej XrSpatialCapabilityConfigurationBaseHeaderEXT funkcji, która obsługuje ten komponent.
Ten komponent nie wymaga żadnej specjalnej konfiguracji, aby można go było uwzględnić w łańcuchu XrSpatialCapabilityConfigurationBaseHeaderEXT :: next.
Tworzenie kotwicy przestrzennej
Funkcja xrCreateSpatialAnchorEXT jest zdefiniowana w ten sposób:
XrResult xrCreateSpatialAnchorEXT(
XrSpatialContextEXT spatialContext,
const XrSpatialAnchorCreateInfoEXT* createInfo,
XrSpatialEntityIdEXT* anchorEntityId,
XrSpatialEntityEXT* anchorEntity);
Opisy parametrów
spatialContextto XrSpatialContextEXT utworzony wcześniej za pomocą xrCreateSpatialContextAsyncEXT .createInfoto wskaźnik do XrSpatialAnchorCreateInfoEXT .anchorEntityIdto wskaźnik doXrSpatialEntityIdEXT, w którym zwracany jest identyfikator elementu kotwicy.anchorEntityto wskaźnik do XrSpatialEntityEXT, w którym zwracany jest uchwyt elementu kotwicy.
Aplikacja może utworzyć kotwicę przestrzenną za pomocą xrCreateSpatialAnchorEXT .
Aby uzyskać zaktualizowane dane komponentu kotwicy, podczas tworzenia migawki przekaż wartość wypełnioną w anchorEntity do XrSpatialUpdateSnapshotCreateInfoEXT :: entities. Aplikacja może użyć anchorEntityId, aby jednoznacznie zidentyfikować tę kotwicę w tablicy XrSpatialComponentDataQueryResultEXT :: entityIds podczas korzystania z xrQuerySpatialComponentDataEXT .
Jeśli XR_SPATIAL_CAPABILITY_ANCHOR_EXT nie został skonfigurowany dla spatialContext, środowisko wykonawcze musi zwrócić XR_ERROR_VALIDATION_FAILURE z xrCreateSpatialAnchorEXT . Informacje o tym, jak skonfigurować XrSpatialContextEXT dla funkcji XR_SPATIAL_CAPABILITY_ANCHOR_EXT, znajdziesz w sekcji Konfiguracja.
Kotwica reprezentowana przez anchorEntity jest ważna tylko przez czas działania spatialContext lub do momentu , gdy aplikacja wywoła dla niej xrDestroySpatialEntityEXT – w zależności od tego, co nastąpi wcześniej. Inne rozszerzenia mogą oferować funkcje umożliwiające zachowanie tej nowo utworzonej kotwicy w wielu sesjach XrSession lub udostępnianie jej między procesami innym aplikacjom.
Nowo utworzona kotwica, dopóki nie zostanie zniszczona, musi być wykrywalna w swoim nadrzędnym kontekście przestrzennym. Oznacza to, że jeśli kotwica pasuje do kryteriów wykrywania ustawionych w XrSpatialDiscoverySnapshotCreateInfoEXT, środowisko wykonawcze musi uwzględnić anchorEntityId w migawce utworzonej za pomocą xrCreateSpatialDiscoverySnapshotAsyncEXT dla spatialContext . Nowo utworzona kotwica może być też wykrywalna w innych kontekstach przestrzennych skonfigurowanych za pomocą XR_SPATIAL_CAPABILITY_ANCHOR_EXT, ale z innym XrSpatialEntityIdEXT, ponieważ konkretny XrSpatialEntityIdEXT jest unikalny dla swojego XrSpatialContextEXT .
Prawidłowe użycie (pośrednie)
- Przed wywołaniem xrCreateSpatialAnchorEXT musi być włączone rozszerzenie
XR_EXT_spatial_anchor. -
spatialContextmusi być prawidłowym uchwytem XrSpatialContextEXT. -
createInfomusi być wskaźnikiem do prawidłowej struktury XrSpatialAnchorCreateInfoEXT. -
anchorEntityIdmusi być wskaźnikiem do wartościXrSpatialEntityIdEXT. -
anchorEntitymusi być wskaźnikiem do uchwytu XrSpatialEntityEXT.
Kody powrotu
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_LIMIT_REACHEDXR_ERROR_OUT_OF_MEMORYXR_ERROR_POSE_INVALIDXR_ERROR_RUNTIME_FAILUREXR_ERROR_SESSION_LOSTXR_ERROR_TIME_INVALIDXR_ERROR_VALIDATION_FAILUREXR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID(jeśli włączone jestXR_ANDROID_spatial_entity_bound_anchor)XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT(jeśli włączone jestXR_ANDROID_spatial_entity_bound_anchor)
Struktura XrSpatialAnchorCreateInfoEXT jest zdefiniowana w ten sposób:
typedef struct XrSpatialAnchorCreateInfoEXT {
XrStructureType type;
const void* next;
XrSpace baseSpace;
XrTime time;
XrPosef pose;
} XrSpatialAnchorCreateInfoEXT;
Opisy elementów
typeto XrStructureType tej struktury.nexttoNULLlub wskaźnik do następnej struktury w łańcuchu struktur.baseSpaceto XrSpace, w którym stosowana jestpose.timetoXrTime, w którym znajduje siębaseSpace(i stosowana jestpose).poseto lokalizacja elementu kotwicy.
Prawidłowe użycie (pośrednie)
- Przed użyciem XrSpatialAnchorCreateInfoEXT musi być włączone rozszerzenie
XR_EXT_spatial_anchor. -
typemusi mieć wartośćXR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT -
nextmusi mieć wartośćNULLlub prawidłowy wskaźnik do następnej struktury w łańcuchu struktur . Zobacz też: XrSpatialAnchorParentANDROID -
baseSpacemusi być prawidłowym uchwytem XrSpace.
Zapytanie o pozę kotwicy
Po utworzeniu kotwicy środowisko wykonawcze powinno dostosowywać jej pozycję i orientację w czasie względem innych przestrzeni, aby zachować jak najlepsze wyrównanie z jej pierwotną lokalizacją w świecie rzeczywistym, nawet jeśli zmienia to jej relację z pierwotnym XrSpatialAnchorCreateInfoEXT :: baseSpace używanym do jej inicjowania.
Aplikacja może użyć xrCreateSpatialUpdateSnapshotEXT z XrSpatialEntityEXT kotwicy, aby utworzyć nowy XrSpatialSnapshotEXT, a następnie wysłać zapytanie o komponent XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT z tej migawki za pomocą xrQuerySpatialComponentDataEXT . Aplikacja może dodać XrSpatialComponentAnchorListEXT do XrSpatialComponentDataQueryResultEXT :: next, aby pobrać najnowsze dane o lokalizacji kotwic.
Środowisko wykonawcze może ustawić stan śledzenia nowo utworzonej kotwicy na XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT . Aplikacja musi odczytywać stan elementu kotwicy podany w XrSpatialComponentDataQueryResultEXT :: entityStates oraz dane komponentu kotwicy elementu tylko wtedy, gdy stan śledzenia to XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT .
Wytyczne dotyczące korzystania z kotwic
- Poza każdej kotwicy dostosowuje się niezależnie od innych kotwic i przestrzeni. Obiekty wirtualne zakotwiczone oddzielnie mogą się przesuwać lub obracać względem siebie, co powoduje naruszenie hierarchii przestrzennej w przypadkach, gdy te obiekty wirtualne powinny pozostać w stałym położeniu względem siebie. W takich przypadkach aplikacja powinna używać tej samej kotwicy dla wszystkich obiektów wirtualnych, które nie poruszają się względem siebie.
- Aplikacja powinna niszczyć wszystkie uchwyty XrSpatialEntityEXT kotwic, które nie są już używane, aby zwolnić zasoby, które środowisko wykonawcze może wykorzystywać do śledzenia tych kotwic.
Przykładowy kod
Konfigurowanie funkcji kotwicy
W tym przykładzie pokazujemy, jak skonfigurować funkcję kotwicy podczas tworzenia kontekstu przestrzennego.
// Create a spatial spatial context
XrSpatialContextEXT spatialContext{};
{
std::vector<XrSpatialComponentTypeEXT> enabledComponents = {
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT,
};
XrSpatialCapabilityConfigurationAnchorEXT anchorConfig{XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT};
anchorConfig.capability = XR_SPATIAL_CAPABILITY_ANCHOR_EXT;
anchorConfig.enabledComponentCount = enabledComponents.size();
anchorConfig.enabledComponents = enabledComponents.data();
std::array<XrSpatialCapabilityConfigurationBaseHeaderEXT*, 1> capabilityConfigs = {
reinterpret_cast<XrSpatialCapabilityConfigurationBaseHeaderEXT*>(&anchorConfig),
};
XrSpatialContextCreateInfoEXT spatialContextCreateInfo{XR_TYPE_SPATIAL_CONTEXT_CREATE_INFO_EXT};
spatialContextCreateInfo.capabilityConfigCount = capabilityConfigs.size();
spatialContextCreateInfo.capabilityConfigs = capabilityConfigs.data();
XrFutureEXT createContextFuture;
CHK_XR(xrCreateSpatialContextAsyncEXT(session, &spatialContextCreateInfo, &createContextFuture));
waitUntilReady(createContextFuture);
XrCreateSpatialContextCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_CONTEXT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialContextCompleteEXT(session, createContextFuture, &completion));
if (completion.futureResult != XR_SUCCESS) {
return;
}
spatialContext = completion.spatialContext;
}
// ...
// Create spatial anchors and get their latest pose in the frame loop.
// ...
CHK_XR(xrDestroySpatialContextEXT(spatialContext));
Tworzenie kotwicy przestrzennej i pobieranie jej lokalizacji
W tym przykładzie pokazujemy, jak utworzyć kotwicę przestrzenną i pobierać jej pozę w każdej klatce.
XrSpatialAnchorCreateInfoEXT createInfo{XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT};
createInfo.baseSpace = localSpace;
createInfo.time = predictedDisplayTime;
createInfo.pose = {{0, 0, 0, 1}, {1, 1, 1}};
XrSpatialEntityIdEXT spatialAnchorEntityId;
XrSpatialEntityEXT spatialAnchorEntity;
CHK_XR(xrCreateSpatialAnchorEXT(spatialContext, &createInfo, &spatialAnchorEntityId, &spatialAnchorEntity));
auto updateAnchorLocation = [&](XrTime time) {
// We want to get updated data for all components of the entities, so skip specifying componentTypes.
XrSpatialUpdateSnapshotCreateInfoEXT snapshotCreateInfo{XR_TYPE_SPATIAL_UPDATE_SNAPSHOT_CREATE_INFO_EXT};
snapshotCreateInfo.entityCount = 1;
snapshotCreateInfo.entities = &spatialAnchorEntity;
snapshotCreateInfo.baseSpace = localSpace;
snapshotCreateInfo.time = time;
XrSpatialSnapshotEXT snapshot;
CHK_XR(xrCreateSpatialUpdateSnapshotEXT(spatialContext, &snapshotCreateInfo, &snapshot));
// Query for the entities that have the anchor component on them.
std::array<XrSpatialComponentTypeEXT, 1> componentsToQuery {XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT};
XrSpatialComponentDataQueryConditionEXT queryCond{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT};
queryCond.componentTypeCount = componentsToQuery.size();
queryCond.componentTypes = componentsToQuery.data();
XrSpatialComponentDataQueryResultEXT queryResult{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT};
CHK_XR(xrQuerySpatialComponentDataEXT(snapshot, &queryCond, &queryResult));
std::vector<XrSpatialEntityIdEXT> entityIds(queryResult.entityIdCountOutput);
std::vector<XrSpatialEntityTrackingStateEXT> entityStates(queryResult.entityIdCountOutput);
queryResult.entityIdCapacityInput = entityIds.size();
queryResult.entityIds = entityIds.data();
queryResult.entityStateCapacityInput = entityStates.size();
queryResult.entityStates = entityStates.data();
// query for the pose data
std::vector<XrPosef> locations(queryResult.entityIdCountOutput);
XrSpatialComponentAnchorListEXT locationList{XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT};
locationList.locationCount = locations.size();
locationList.locations = locations.data();
queryResult.next = &locationList;
CHK_XR(xrQuerySpatialComponentDataEXT(snapshot, &queryCond, &queryResult));
for (int32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
if (entityStates[i] == XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT) {
// Pose for entity entityIds[i] is locations[i].
}
}
CHK_XR(xrDestroySpatialSnapshotEXT(snapshot));
};
while (1) {
// ...
// For every frame in frame loop
// ...
XrFrameState frameState; // previously returned from xrWaitFrame
const XrTime time = frameState.predictedDisplayTime;
updateAnchorLocation(time);
// ...
// Finish frame loop
// ...
}
CHK_XR(xrDestroySpatialEntityEXT(spatialAnchorEntity));
Nowe polecenia
Nowe struktury
- XrSpatialAnchorCreateInfoEXT
- XrSpatialCapabilityConfigurationAnchorEXT
Rozszerzanie XrSpatialComponentDataQueryResultEXT :
Nowe stałe wyliczeniowe
XR_EXT_SPATIAL_ANCHOR_EXTENSION_NAMEXR_EXT_spatial_anchor_SPEC_VERSIONRozszerzanie XrSpatialCapabilityEXT :
XR_SPATIAL_CAPABILITY_ANCHOR_EXT
Rozszerzanie XrSpatialComponentTypeEXT :
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
Rozszerzanie XrStructureType :
XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXTXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXTXR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT
Problemy
Dlaczego xrCreateSpatialAnchorEXT zwraca zarówno identyfikator elementu, jak i uchwyt elementu?
- Rozwiązane
- Odpowiedź: funkcja xrCreateSpatialAnchorEXT mogła równie dobrze zwracać tylko identyfikator elementu, a aplikacje mogłyby tworzyć uchwyt elementu dla tego identyfikatora za pomocą xrCreateSpatialEntityFromIdEXT . Jednak biorąc pod uwagę typowe użycie kotwicy, w którym aplikacje wysyłają zapytanie o pozę kotwicy w każdej klatce, staje się ona dobrym kandydatem do użycia w „migawce aktualizacji”, która wymaga uchwytów elementów jako danych wejściowych. Przewidując ten typowy przypadek użycia, xrCreateSpatialAnchorEXT wykonuje xrCreateSpatialEntityFromIdEXT w imieniu aplikacji i udostępnia jej uchwyt elementu do użycia z xrCreateSpatialUpdateSnapshotEXT .
Historia zmian
Wersja 1, 10.07.2024 (Nihav Jain, Google)
- Początkowy opis rozszerzenia