XR_EXT_spatial_anchor
String do nome
XR_EXT_spatial_anchor
Tipo de extensão
Extensão de instância
Número de extensão registrada
763
Revisão
1
Status de ratificação
Ratificações
Dependências de extensão e versão
XR_EXT_spatial_entity
Colaboradores
Nihav Jain, Google
Natalie Fleury, Meta
Yuichi Taguchi, Meta
Ron Bessems, Meta
Yin Li, Microsoft
Jimmy Alamparambil, ByteDance
Zhipeng Liu, ByteDance
Jun Yan, ByteDance
Visão geral
Essa extensão se baseia em XR_EXT_spatial_entity e permite que os aplicativos criem âncoras espaciais, que são pontos arbitrários no ambiente físico do usuário que serão rastreados pelo ambiente de execução. O ambiente de execução precisa ajustar a posição e a orientação da origem da âncora ao longo do tempo, conforme necessário, independente de todos os outros espaços e âncoras, para garantir que ela mantenha o mapeamento original para o mundo real.
Uma âncora que rastreia uma determinada posição e orientação em um XrSpatialContextEXT é representada como uma entidade espacial com (ou "que tem") o XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT componente.
Benefício de usar âncoras
À medida que a compreensão do ambiente físico do usuário pelo ambiente de execução é atualizada durante o ciclo de vida de um XrSpatialContextEXT , os objetos virtuais podem parecer se afastar de onde foram colocados pelo aplicativo, o que afeta o realismo do aplicativo e a qualidade da experiência do usuário. Ao criar uma âncora perto de onde um objeto virtual é colocado e, em seguida, sempre renderizar esse objeto virtual em relação à âncora, um aplicativo pode garantir que cada objeto virtual pareça permanecer na mesma posição e orientação no ambiente físico. Além disso, ao contrário de determinados espaços de referência, as âncoras não são afetadas pela recentralização no nível do sistema.
Suporte ao ambiente de execução
Se o ambiente de execução oferece suporte a âncoras espaciais, ele precisa indicar isso enumerando XR_SPATIAL_CAPABILITY_ANCHOR_EXT em xrEnumerateSpatialCapabilitiesEXT .
Configuração
A estrutura XrSpatialCapabilityConfigurationAnchorEXT é definida como:
typedef struct XrSpatialCapabilityConfigurationAnchorEXT {
XrStructureType type;
const void* next;
XrSpatialCapabilityEXT capability;
uint32_t enabledComponentCount;
const XrSpatialComponentTypeEXT* enabledComponents;
} XrSpatialCapabilityConfigurationAnchorEXT;
Descrições de membros
typeé o XrStructureType dessa estrutura.nextéNULLou um ponteiro para a próxima estrutura em uma cadeia de estruturas.capabilityé um XrSpatialCapabilityEXT .enabledComponentCounté umuint32_tque descreve a contagem de elementos na matrizenabledComponents.enabledComponentsé um ponteiro para uma matriz de XrSpatialComponentTypeEXT .
Os aplicativos podem ativar o recurso espacial XR_SPATIAL_CAPABILITY_ANCHOR_EXT incluindo um ponteiro para uma estrutura XrSpatialCapabilityConfigurationAnchorEXT em XrSpatialContextCreateInfoEXT :: capabilityConfigs .
O ambiente de execução precisa retornar XR_ERROR_VALIDATION_FAILURE se capability não for XR_SPATIAL_CAPABILITY_ANCHOR_EXT .
Uso válido (implícito)
- A extensão
XR_EXT_spatial_anchorprecisa ser ativada antes de usar XrSpatialCapabilityConfigurationAnchorEXT -
typeprecisa serXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT -
nextprecisa serNULLou um ponteiro válido para a próxima estrutura em uma cadeia de estruturas -
capabilityprecisa ser um valor XrSpatialCapabilityEXT válido -
enabledComponentsprecisa ser um ponteiro para uma matriz deenabledComponentCountvalores XrSpatialComponentTypeEXT válidos. - O parâmetro
enabledComponentCountprecisa ser maior que0
Componentes garantidos
Um ambiente de execução que oferece suporte a XR_SPATIAL_CAPABILITY_ANCHOR_EXT precisa fornecer os seguintes componentes espaciais como componentes garantidos de todas as entidades criadas ou descobertas por esse recurso e precisa enumerá-los em xrEnumerateSpatialCapabilityComponentTypesEXT :
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
Componente de âncora
Dados do componente
O XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT usa XrPosef para os dados, que fornecem a posição e a orientação da âncora.
Estrutura da lista de componentes para consultar dados
A estrutura XrSpatialComponentAnchorListEXT é definida como:
typedef struct XrSpatialComponentAnchorListEXT {
XrStructureType type;
void* next;
uint32_t locationCount;
XrPosef* locations;
} XrSpatialComponentAnchorListEXT;
Descrições de membros
typeé o XrStructureType dessa estrutura.nextéNULLou um ponteiro para a próxima estrutura em uma cadeia de estruturas.locationCounté umuint32_tque descreve a contagem de elementos na matrizlocations.locationsé uma matriz de XrPosef .
O ambiente de execução precisa retornar XR_ERROR_VALIDATION_FAILURE de xrQuerySpatialComponentDataEXT se XrSpatialComponentAnchorListEXT estiver na cadeia XrSpatialComponentDataQueryResultEXT :: next, mas XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT não estiver incluído em XrSpatialComponentDataQueryConditionEXT :: componentTypes .
O ambiente de execução precisa retornar XR_ERROR_SIZE_INSUFFICIENT de xrQuerySpatialComponentDataEXT se locationCount for menor que XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput .
Uso válido (implícito)
- A extensão
XR_EXT_spatial_anchorprecisa ser ativada antes de usar XrSpatialComponentAnchorListEXT. -
typeprecisa serXR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT -
nextprecisa serNULLou um ponteiro válido para a próxima estrutura em uma cadeia de estruturas -
locationsprecisa ser um ponteiro para uma matriz delocationCountXrPosef estruturas - O parâmetro
locationCountprecisa ser maior que0
Configuração
Se XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT for enumerado em XrSpatialCapabilityComponentTypesEXT :: componentTypes para algum recurso, um aplicativo poderá ativá-lo incluindo o enumerador na lista XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents da estrutura derivada XrSpatialCapabilityConfigurationBaseHeaderEXT do recurso que oferece suporte a esse componente.
Esse componente não exige nenhuma configuração especial para ser incluído na cadeia XrSpatialCapabilityConfigurationBaseHeaderEXT :: next.
Como criar uma âncora espacial
A função xrCreateSpatialAnchorEXT é definida como:
XrResult xrCreateSpatialAnchorEXT(
XrSpatialContextEXT spatialContext,
const XrSpatialAnchorCreateInfoEXT* createInfo,
XrSpatialEntityIdEXT* anchorEntityId,
XrSpatialEntityEXT* anchorEntity);
Descrições dos parâmetros
spatialContexté um XrSpatialContextEXT criado anteriormente usando xrCreateSpatialContextAsyncEXT .createInfoé um ponteiro para um XrSpatialAnchorCreateInfoEXT .anchorEntityIdé um ponteiro para umXrSpatialEntityIdEXTem que o ID da entidade de âncora é retornado.anchorEntityé um ponteiro para um XrSpatialEntityEXT em que o identificador da entidade de âncora é retornado.
O aplicativo pode criar uma âncora espacial usando xrCreateSpatialAnchorEXT .
Para receber dados de componentes atualizados de uma âncora, transmita o valor preenchido em anchorEntity para XrSpatialUpdateSnapshotCreateInfoEXT :: entities ao criar um snapshot. O aplicativo pode usar anchorEntityId para identificar exclusivamente essa âncora na matriz XrSpatialComponentDataQueryResultEXT :: entityIds ao usar xrQueryComponentDataEXT .
O ambiente de execução precisa retornar XR_ERROR_VALIDATION_FAILURE de xrCreateSpatialAnchorEXT se XR_SPATIAL_CAPABILITY_ANCHOR_EXT não estiver configurado para spatialContext . Consulte Configuração para saber como configurar um XrSpatialContextEXT para o recurso XR_SPATIAL_CAPABILITY_ANCHOR_EXT.
A âncora representada por anchorEntity só é válida durante o ciclo de vida de spatialContext ou até que o aplicativo chame xrDestroySpatialEntityEXT nela, o que ocorrer primeiro. Outras extensões podem oferecer funções para persistir essa âncora recém-criada em vários XrSession ou para compartilhá-la entre limites de processos com outros aplicativos.
Uma âncora recém-criada, até ser destruída, precisa ser detectável no contexto espacial pai. Isso significa que o ambiente de execução precisa incluir anchorEntityId no snapshot criado usando xrCreateSpatialDiscoverySnapshotAsyncEXT para spatialContext se a âncora corresponder aos critérios de descoberta definidos em XrSpatialDiscoverySnapshotCreateInfoEXT . A âncora recém-criada também pode ser detectável em outros contextos espaciais configurados com XR_SPATIAL_CAPABILITY_ANCHOR_EXT, embora com um XrSpatialEntityIdEXT diferente, já que um XrSpatialEntityIdEXT específico é exclusivo do XrSpatialContextEXT .
Uso válido (implícito)
- A extensão
XR_EXT_spatial_anchorprecisa ser ativada antes de chamar xrCreateSpatialAnchorEXT. -
spatialContextprecisa ser um identificador XrSpatialContextEXT válido. -
createInfoprecisa ser um ponteiro para uma estrutura XrSpatialAnchorCreateInfoEXT válida. -
anchorEntityIdprecisa ser um ponteiro para um valorXrSpatialEntityIdEXT. -
anchorEntityprecisa ser um ponteiro para um identificador XrSpatialEntityEXT.
Códigos de retorno
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(seXR_ANDROID_spatial_entity_bound_anchorestiver ativado)XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT(seXR_ANDROID_spatial_entity_bound_anchorestiver ativado)
A estrutura XrSpatialAnchorCreateInfoEXT é definida como:
typedef struct XrSpatialAnchorCreateInfoEXT {
XrStructureType type;
const void* next;
XrSpace baseSpace;
XrTime time;
XrPosef pose;
} XrSpatialAnchorCreateInfoEXT;
Descrições de membros
typeé o XrStructureType dessa estrutura.nextéNULLou um ponteiro para a próxima estrutura em uma cadeia de estruturas.baseSpaceé o XrSpace em queposeé aplicado.timeé oXrTimeem quebaseSpaceestá localizado (eposeé aplicado).poseé o local da entidade de âncora.
Uso válido (implícito)
- A extensão
XR_EXT_spatial_anchorprecisa ser ativada antes de usar XrSpatialAnchorCreateInfoEXT. -
typeprecisa serXR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT -
nextprecisa serNULLou um ponteiro válido para a próxima estrutura em uma cadeia de estruturas . Consulte também: XrSpatialAnchorParentANDROID -
baseSpaceprecisa ser um identificador XrSpace válido.
Consultar a pose da âncora
Depois que a âncora é criada, o ambiente de execução precisa ajustar a posição e a orientação dela ao longo do tempo em relação a outros espaços para manter o melhor alinhamento possível com o local original do mundo real, mesmo que isso mude a relação da âncora com o XrSpatialAnchorCreateInfoEXT :: baseSpace original usado para inicializá-la.
O aplicativo pode usar xrCreateSpatialUpdateSnapshotEXT com o XrSpatialEntityEXT da âncora para criar um novo XrSpatialSnapshotEXT e, em seguida, consultar o componente XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT desse snapshot usando xrQuerySpatialComponentDataEXT . O aplicativo pode adicionar XrSpatialComponentAnchorListEXT a XrSpatialComponentDataQueryResultEXT :: next para recuperar os dados de localização mais recentes das âncoras.
O ambiente de execução pode definir o estado de rastreamento de uma âncora recém-criada como XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT . O aplicativo precisa ler apenas o estado da entidade de âncora fornecido em XrSpatialComponentDataQueryResultEXT :: entityStates e os dados do componente de âncora da entidade se o estado de rastreamento for XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT .
Diretrizes para usar âncoras
- A pose de cada âncora é ajustada independentemente de qualquer outra âncora ou espaço. Objetos virtuais ancorados separadamente podem mudar ou girar em relação uns aos outros, quebrando a hierarquia espacial nos casos em que esses objetos virtuais precisam permanecer no lugar em relação uns aos outros. Nesses casos, o aplicativo precisa reutilizar a mesma âncora para todos os objetos virtuais que não se movem em relação uns aos outros.
- O aplicativo precisa destruir todos os identificadores XrSpatialEntityEXT de âncoras que não estão mais sendo usadas para liberar os recursos que o ambiente de execução pode estar usando para rastrear essas âncoras.
Código de exemplo
Configurar o recurso de âncora
O exemplo a seguir demonstra como configurar o recurso de âncora ao criar um contexto espacial.
// 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));
Criar uma âncora espacial e receber a localização dela
O exemplo a seguir demonstra como criar uma âncora espacial e receber a pose dela a cada frame.
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));
Novos comandos
Novas estruturas
- XrSpatialAnchorCreateInfoEXT
- XrSpatialCapabilityConfigurationAnchorEXT
Estendendo XrSpatialComponentDataQueryResultEXT :
Novas constantes de tipo enumerado
XR_EXT_SPATIAL_ANCHOR_EXTENSION_NAMEXR_EXT_spatial_anchor_SPEC_VERSIONEstendendo XrSpatialCapabilityEXT :
XR_SPATIAL_CAPABILITY_ANCHOR_EXT
Estendendo XrSpatialComponentTypeEXT :
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
Estendendo XrStructureType :
XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXTXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXTXR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT
Problemas
Por que xrCreateSpatialAnchorEXT gera um ID de entidade e um identificador de entidade?
- Resolvido
- Resposta: a função xrCreateSpatialAnchorEXT poderia muito bem ter fornecido apenas o ID da entidade como saída, e os aplicativos poderiam criar um identificador de entidade para esse ID usando xrCreateSpatialEntityFromIdEXT . No entanto, considerando o uso típico de uma âncora em que os aplicativos consultam a pose da âncora a cada frame, ela se torna um bom candidato para ser usada em um "snapshot de atualização", que exige identificadores de entidade como entrada. Antecipando esse caso de uso típico, xrCreateSpatialAnchorEXT executa xrCreateSpatialEntityFromIdEXT em nome do aplicativo e fornece a ele o identificador de entidade para usar com xrCreateSpatialUpdateSnapshotEXT .
Histórico de versões
Revisão 1, 10/07/2024 (Nihav Jain, Google)
- Descrição inicial da extensão