XR_ANDROID_spatial_entity_bound_anchor
String Nama
XR_ANDROID_spatial_entity_bound_anchor
Jenis Ekstensi
Ekstensi instance
Nomor Ekstensi Terdaftar
791
Revisi
2
Status Ratifikasi
Tidak diratifikasi
Dependensi Ekstensi dan Versi
XR_EXT_spatial_anchor
Tanggal Terakhir Diubah
2025-08-18
Status IP
Tidak ada klaim IP yang diketahui.
Kontributor
YuSheng Chang, Google
Kyle Chen, Google
Nihav Jain, Google
Levana Chen, Google
Spencer Quin, Google
Ringkasan
Ekstensi ini memungkinkan aplikasi membuat dan melampirkan anchor ke entity spasial, yang disebut "anchor terikat entity" dalam ekstensi ini.
Anchor yang terikat entitas direpresentasikan sebagai entitas spasial dengan (atau "yang memiliki") komponen XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT dan komponen XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT. Komponen XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT menyimpan XrSpatialEntityIdEXT dari parent entity tempat anchor dilampirkan.
Pose anchor yang terikat entity selalu direpresentasikan oleh offset tetap dari entity induknya, yang dianggap sebagai "dasar" anchor. Misalnya, bayangkan pengguna memiliki bingkai foto virtual yang terpasang di dinding, pengguna menggunakan anchor terikat entitas untuk merepresentasikan bingkai foto virtual, dan memasangnya ke entitas dinding. Dengan demikian, posisi relatif antara dinding dan bingkai foto akan selalu konsisten seiring peningkatan estimasi pelacakan dinding fisik.
Dukungan Runtime
Runtime harus mendukung setidaknya satu ekstensi pelacakan spasial, misalnya XR_EXT_spatial_plane_tracking . Jika runtime mendukung anchor terikat entity spasial, runtime harus menyediakan setidaknya satu komponen yang dapat dilampirkan dengan mengenumerasi fungsi xrEnumerateSpatialAnchorAttachableComponentsANDROID. Aplikasi dapat menghitung komponen yang dapat dilampirkan dengan menggunakan xrEnumerateSpatialAnchorAttachableComponentsANDROID .
Fungsi xrEnumerateSpatialAnchorAttachableComponentsANDROID ditentukan sebagai:
XrResult xrEnumerateSpatialAnchorAttachableComponentsANDROID(
XrInstance instance,
XrSystemId systemId,
uint32_t attachableComponentCapacityInput,
uint32_t* attachableComponentCountOutput,
XrSpatialComponentTypeEXT* attachableComponents);
Deskripsi Parameter
instanceadalah tuas untuk XrInstance .systemIdadalahXrSystemIdyang persisten secara spasial dan toko-tokonya akan dihitung.attachableComponentCapacityInputadalah kapasitas arrayattachableComponents, atau 0 untuk menunjukkan permintaan guna mengambil kapasitas yang diperlukan.attachableComponentCountOutputadalah jumlah komponen yang dapat dilampirkan, atau kapasitas yang diperlukan jikaattachableComponentCapacityInputtidak mencukupi.attachableComponentsadalah array XrSpatialComponentTypeEXT . Nilainya dapat berupaNULLjikaattachableComponentCapacityInputadalah 0.- Lihat bab Parameter Ukuran Buffer untuk mengetahui deskripsi mendetail tentang pengambilan ukuran
attachableComponentsyang diperlukan.
Runtime harus selalu menampilkan konten buffer yang identik dari enumerasi ini untuk systemId tertentu selama masa aktif instance.
Penggunaan yang Valid (Implisit)
- Ekstensi
XR_ANDROID_spatial_entity_bound_anchorharus diaktifkan sebelum memanggil xrEnumerateSpatialAnchorAttachableComponentsANDROID -
instanceharus berupa handle XrInstance yang valid -
attachableComponentCountOutputharus berupa pointer ke nilaiuint32_t - Jika
attachableComponentCapacityInputbukan0,attachableComponentsharus berupa pointer ke array nilaiattachableComponentCapacityInputXrSpatialComponentTypeEXT
Kode Status
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_RUNTIME_FAILUREXR_ERROR_SIZE_INSUFFICIENTXR_ERROR_SYSTEM_INVALIDXR_ERROR_VALIDATION_FAILURE
Membuat anchor terikat entitas spasial
Aplikasi menggunakan fungsi xrCreateSpatialAnchorEXT untuk membuat anchor. Jika aplikasi ingin membuat anchor terikat entity yang terpasang ke entity spasial, aplikasi dapat merangkai struktur XrSpatialAnchorParentANDROID ke pointer berikutnya dari struktur XrSpatialAnchorCreateInfoEXT saat memanggil fungsi xrCreateSpatialAnchorEXT.
Struktur XrSpatialAnchorParentANDROID ditentukan sebagai:
typedef struct XrSpatialAnchorParentANDROID {
XrStructureType type;
const void* next;
XrSpatialEntityIdEXT parentId;
} XrSpatialAnchorParentANDROID;
Deskripsi Anggota
typeadalah XrStructureType dari struktur ini.nextadalahNULLatau pointer ke struktur berikutnya dalam rantai struktur.parentIdadalahXrSpatialEntityIdEXTentity yang akan dilampiri anchor.
Runtime harus menjamin bahwa jarak antara entity induk dan anchor selalu konsisten, dengan jarak adalah pose anchor ke permukaan terdekat entity induk di sepanjang normal permukaan. Pose anchor diperbarui berdasarkan posisi entity induk dan jarak ke permukaan entity induk, terlepas dari jumlah komponen yang dapat dilampirkan yang dimiliki entity induk.
Runtime harus menampilkan XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT dari xrCreateSpatialAnchorEXT jika XrSpatialAnchorParentANDROID ::parentId bukan ID yang valid untuk xrCreateSpatialAnchorEXT :: spatialContext .
Runtime harus menampilkan XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID dari xrCreateSpatialAnchorEXT jika tidak ada komponen yang tercantum oleh xrEnumerateSpatialAnchorAttachableComponentsANDROID pada parent entity.
Penggunaan yang Valid (Implisit)
- Ekstensi
XR_ANDROID_spatial_entity_bound_anchorharus diaktifkan sebelum menggunakan XrSpatialAnchorParentANDROID -
typeharus berupaXR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROID -
nextharus berupaNULLatau pointer yang valid ke struktur berikutnya dalam rantai struktur
Kode contoh
Membuat anchor terikat entitas spasial
Contoh kode berikut menunjukkan cara membuat penanda terikat entitas dan melampirkannya ke entitas pelacakan bidang spasial.
XrFutureEXT future {XR_NULL_FUTURE_EXT};
std::vector<XrSpatialEntityEXT> entityBoundAnchorEntities;
// We want to look for entities that have the plane tracking components.
std::vector<XrSpatialComponentTypeEXT> snapshotComponents = {
XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT,
XR_SPATIAL_COMPONENT_TYPE_PLANE_ALIGNMENT_EXT,
};
auto discoverSpatialEntities = [&](XrSpatialContextEXT spatialContext, XrTime time) {
XrSpatialDiscoverySnapshotCreateInfoEXT snapshotCreateInfo{
.type = XR_TYPE_SPATIAL_DISCOVERY_SNAPSHOT_CREATE_INFO_EXT,
.componentTypeCount = static_cast<uint32_t>(snapshotComponents.size()),
.componentTypes = snapshotComponents.data(),
};
CHK_XR(xrCreateSpatialDiscoverySnapshotAsyncEXT(spatialContext, &snapshotCreateInfo, &future));
waitUntilReady(future);
XrCreateSpatialDiscoverySnapshotCompletionInfoEXT completionInfo{
.type = XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_INFO_EXT,
.baseSpace = localSpace,
.time = time,
.future = future,
};
XrCreateSpatialDiscoverySnapshotCompletionEXT completion{
.type = XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_EXT,
};
CHK_XR(xrCreateSpatialDiscoverySnapshotCompleteEXT(spatialContext, &completionInfo, &completion));
if (completion.futureResult == XR_SUCCESS) {
XrSpatialComponentDataQueryConditionEXT queryCond{
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT,
.componentTypeCount = static_cast<uint32_t>(snapshotComponents.size()),
.componentTypes = snapshotComponents.data(),
};
XrSpatialComponentDataQueryResultEXT queryResult{
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT,
};
CHK_XR(xrQuerySpatialComponentDataEXT(completion.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();
std::vector<XrSpatialBounded2DDataEXT> bounded2D(queryResult.entityIdCountOutput);
XrSpatialComponentBounded2DListEXT bounded2DList{
.type = XR_TYPE_SPATIAL_COMPONENT_BOUNDED_2D_LIST_EXT,
.boundCount = static_cast<uint32_t>(bounded2D.size()),
.bounds = bounded2D.data(),
};
queryResult.next = &bounded2DList;
CHK_XR(xrQuerySpatialComponentDataEXT(completion.snapshot, &queryCond, &queryResult));
entityBoundAnchorEntities.reserve(queryResult.entityIdCountOutput);
// Create anchors attached to the plane entities
for (int32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
if (entityStates[i] != XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT) {
continue;
}
// Parent ID info the chained to spatial anchor create info next
XrSpatialAnchorParentANDROID parentIdCreateInfo{
.type = XR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROID,
.parentId = entityIds[i],
};
// spatial anchor create info
XrSpatialAnchorCreateInfoEXT createInfo{
.type = XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT,
// assign Parent ID to anchor create info next, and the pose to the bounded2D center
.next = &parentIdCreateInfo,
.baseSpace = localSpace,
.time = time,
.pose = bounded2D[i].center,
};
XrSpatialEntityIdEXT entityBoundAnchorEntityId {XR_NULL_SPATIAL_ENTITY_ID_EXT};
XrSpatialEntityEXT entityBoundAnchorEntity {XR_NULL_HANDLE};
CHK_XR(xrCreateSpatialAnchorEXT(spatialContext, &createInfo, &entityBoundAnchorEntityId, &entityBoundAnchorEntity));
entityBoundAnchorEntities.push_back(entityBoundAnchorEntity);
}
CHK_XR(xrDestroySpatialSnapshotEXT(completion.snapshot));
}
};
while (1) {
// ...
// For every frame in frame loop
// ...
XrFrameState frameState; // previously returned from xrWaitFrame
const XrTime time = frameState.predictedDisplayTime;
// Poll for the XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT event
XrEventDataBuffer event = {
.type = XR_TYPE_EVENT_DATA_BUFFER,
};
XrResult result = xrPollEvent(instance, &event);
if (result == XR_SUCCESS) {
if (event.type == XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT) {
const XrEventDataSpatialDiscoveryRecommendedEXT& eventdata =
*reinterpret_cast<XrEventDataSpatialDiscoveryRecommendedEXT*>(&event);
// Discover spatial entities for the context that we received the "discovery
// recommended" event for.
discoverSpatialEntities(eventdata.spatialContext, time);
break;
}
}
// ...
// Finish frame loop
// ...
}
Mendapatkan pose anchor terikat entitas dan ID entitas induk
Contoh kode berikut menunjukkan cara mendapatkan pose anchor terikat entity dan ID entity induknya.
std::vector<XrSpatialEntityEXT> entities;
auto updateEntityBoundAnchorInfo = [&](XrSpatialContextEXT spatialContext, XrTime time) {
// We want to get updated data for all components of the entities, so skip specifying componentTypes.
XrSpatialUpdateSnapshotCreateInfoEXT snapshotCreateInfo{
.type = XR_TYPE_SPATIAL_UPDATE_SNAPSHOT_CREATE_INFO_EXT,
.entityCount = static_cast<uint32_t>(entities.size()),
.entities = entities.data(),
.baseSpace = localSpace,
.time = time,
};
XrSpatialSnapshotEXT snapshot {XR_NULL_HANDLE};
CHK_XR(xrCreateSpatialUpdateSnapshotEXT(spatialContext, &snapshotCreateInfo, &snapshot));
// Query for the entities that have the anchor component and parent component on them.
std::array<XrSpatialComponentTypeEXT, 2> componentsToQuery {XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT, XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT};
XrSpatialComponentDataQueryConditionEXT queryCond{
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT,
.componentTypeCount = componentsToQuery.size(),
.componentTypes = componentsToQuery.data(),
};
XrSpatialComponentDataQueryResultEXT queryResult{
.type = 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{
.type = XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT,
.locationCount = static_cast<uint32_t>(locations.size()),
.locations = locations.data(),
};
queryResult.next = &locationList;
// query for the parent entity ID data
std::vector<XrSpatialEntityIdEXT> parentIds(queryResult.entityIdCountOutput);
XrSpatialComponentParentListEXT parentList{
.type = XR_TYPE_SPATIAL_COMPONENT_PARENT_LIST_EXT,
.parentCount = static_cast<uint32_t>(parentIds.size()),
.parents = parentIds.data(),
};
queryResult.next = &parentList;
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].
// Parent entity ID for entity entityIds[i] is parentIds[i].
}
}
CHK_XR(xrDestroySpatialSnapshotEXT(snapshot));
};
while (1) {
// ...
// For every frame in frame loop
// ...
XrFrameState frameState; // previously returned from xrWaitFrame
const XrTime time = frameState.predictedDisplayTime;
updateEntityBoundAnchorInfo(spatialContext, time);
// ...
// Finish frame loop
// ...
}
Menghitung Komponen yang dapat dilampirkan dan memeriksa kemampuan penanda terikat entity
Contoh kode berikut menunjukkan cara menghitung komponen yang dapat dilampirkan dan memeriksa apakah runtime mendukung kemampuan penanda terikat entitas.
// Check spatial capability
uint32_t capabilityCount = 0;
CHK_XR(xrEnumerateSpatialCapabilitiesEXT(instance, systemId, 0, &capabilityCount, nullptr));
std::vector<XrSpatialCapabilityEXT> capabilities(capabilityCount);
CHK_XR(xrEnumerateSpatialCapabilitiesEXT(instance, systemId, capabilityCount, &capabilityCount, capabilities.data()));
// Check if anchor capability is supported
if (std::find(capabilities.begin(), capabilities.end(), XR_SPATIAL_CAPABILITY_ANCHOR_EXT) == capabilities.end()) {
return;
}
// Check if plane tracking capability is supported
if (std::find(capabilities.begin(), capabilities.end(), XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT) == capabilities.end()) {
return;
}
// The supported spatial tracking components
std::vector<XrSpatialComponentTypeEXT> spatialTrackingCapabilityComponents;
// Enumerate supported components for plane tracking capability
XrSpatialCapabilityComponentTypesEXT planeComponents{
.type = XR_TYPE_SPATIAL_CAPABILITY_COMPONENT_TYPES_EXT,
};
CHK_XR(xrEnumerateSpatialCapabilityComponentTypesEXT(instance, systemId, XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, &planeComponents));
std::vector<XrSpatialComponentTypeEXT> planeCapabilityComponents(planeComponents.componentTypeCountOutput);
planeComponents.componentTypes = planeCapabilityComponents.data();
CHK_XR(xrEnumerateSpatialCapabilityComponentTypesEXT(instance, systemId, XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, &planeComponents));
// Add plane supported components to spatial tracking supported components
spatialTrackingCapabilityComponents.insert(spatialTrackingCapabilityComponents.end(), planeCapabilityComponents.begin(), planeCapabilityComponents.end());
// Enumerate supported attachable components for anchor
uint32_t attachableComponentCount = 0;
CHK_XR(xrEnumerateSpatialAnchorAttachableComponentsANDROID(instance, systemId, 0, &attachableComponentCount, nullptr));
std::vector<XrSpatialComponentTypeEXT> attachableComponents(attachableComponentCount);
CHK_XR(xrEnumerateSpatialAnchorAttachableComponentsANDROID(instance, systemId, attachableComponentCount, &attachableComponentCount, attachableComponents.data()));
// Check if at least one spatial tracking component is supported
const auto supportsComponent = [&spatialTrackingCapabilityComponents](XrSpatialComponentTypeEXT component) {
return std::find(spatialTrackingCapabilityComponents.begin(), spatialTrackingCapabilityComponents.end(), component) != spatialTrackingCapabilityComponents.end();
};
bool atLeastOneComponentSupported = false;
for (int32_t i = 0; i < attachableComponentCount; ++i) {
if(supportsComponent(attachableComponents[i])) {
atLeastOneComponentSupported = true;
break;
}
}
// No spatial tracking component supported for anchor attachment
if(!atLeastOneComponentSupported) return;
// ...
// Create spatial entity anchors and get their latest pose in the frame loop.
// ...
Perintah Baru
Struktur Baru
Memperluas XrSpatialAnchorCreateInfoEXT :
Konstanta Enum Baru
XR_ANDROID_SPATIAL_ENTITY_BOUND_ANCHOR_EXTENSION_NAMEXR_ANDROID_spatial_entity_bound_anchor_SPEC_VERSIONMemperluas XrResult :
XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID
Memperluas XrStructureType :
XR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROID
Masalah
Riwayat Versi
Revisi 1, 18-08-2025 (YuSheng Chang)
- Deskripsi ekstensi awal.
Revisi 2, 16-12-2025 (Kyle Chen)
- Menambahkan bahasa yang lebih preskriptif ke perilaku tertentu API.
- Tambahkan contoh kode xrEnumerateSpatialAnchorAttachableComponentsANDROID .