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
Belum diratifikasi
Dependensi Ekstensi dan Versi
XR_EXT_spatial_anchor
Tanggal Terakhir Diubah
2025-08-18
Status IP
Tidak ada klaim kekayaan intelektual 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 memasang anchor ke entity spasial, yang disebut "anchor terikat entity" dalam ekstensi ini.
Anchor terikat entity direpresentasikan sebagai entity 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 parent entity tempat anchor dipasang.
Pose anchor yang terikat entity selalu direpresentasikan oleh offset tetap dari parent entity-nya, yang dianggap sebagai "dasar" anchor. Misalnya, bayangkan pengguna memiliki bingkai foto virtual yang terpasang di dinding, pengguna menggunakan anchor terikat entity untuk mewakili bingkai foto virtual, dan memasangnya ke entity dinding. Dengan demikian, posisi relatif antara dinding dan bingkai foto 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 dipasang dengan menghitung fungsi xrEnumerateSpatialAnchorAttachableComponentsANDROID. Aplikasi dapat menghitung komponen yang dapat dipasang menggunakan xrEnumerateSpatialAnchorAttachableComponentsANDROID .
Fungsi xrEnumerateSpatialAnchorAttachableComponentsANDROID didefinisikan sebagai:
XrResult xrEnumerateSpatialAnchorAttachableComponentsANDROID(
XrInstance instance,
XrSystemId systemId,
uint32_t attachableComponentCapacityInput,
uint32_t* attachableComponentCountOutput,
XrSpatialComponentTypeEXT* attachableComponents);
Deskripsi Parameter
instanceadalah handle ke XrInstance .systemIdadalahXrSystemIdyang penyimpanan persistensi spasialnya akan dihitung.attachableComponentCapacityInputadalah kapasitas arrayattachableComponents, atau 0 untuk menunjukkan permintaan guna mengambil kapasitas yang diperlukan.attachableComponentCountOutputadalah jumlah komponen yang dapat dipasang, atau kapasitas yang diperlukan jikaattachableComponentCapacityInputtidak mencukupi.attachableComponentsadalah array XrSpatialComponentTypeEXT . Nilainya bisaNULLjikaattachableComponentCapacityInputadalah 0.- Lihat bab Parameter Ukuran Buffer untuk mengetahui deskripsi mendetail tentang cara mengambil ukuran
attachableComponentsyang diperlukan.
Runtime harus selalu menampilkan konten buffer yang identik dari enumerasi ini untuk systemId yang diberikan 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 entity spasial
Aplikasi menggunakan fungsi xrCreateSpatialAnchorEXT untuk membuat anchor. Jika aplikasi ingin membuat anchor terikat entity yang dilampirkan ke entity spasial, aplikasi dapat merantai struktur XrSpatialAnchorParentANDROID ke pointer berikutnya dari struktur XrSpatialAnchorCreateInfoEXT saat memanggil fungsi xrCreateSpatialAnchorEXT.
Struktur XrSpatialAnchorParentANDROID didefinisikan 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 tempat anchor akan dipasang.
Runtime harus menjamin bahwa jarak antara entity induk dan anchor selalu konsisten, dengan jarak tersebut adalah pose anchor ke permukaan terdekat entity induk di sepanjang permukaan normal. Pose anchor diperbarui berdasarkan posisi entity induk dan jarak ke permukaan entity induk, terlepas dari jumlah komponen yang dapat dipasang 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 dihitung oleh xrEnumerateSpatialAnchorAttachableComponentsANDROID yang ada di 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 entity spasial
Kode contoh berikut menunjukkan cara membuat anchor terikat entity dan memasangnya ke entity 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 yang terikat entity dan ID entity induk
Kode contoh berikut menunjukkan cara mendapatkan pose anchor yang 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 dipasang dan memeriksa kemampuan anchor terikat entity
Kode contoh berikut menunjukkan cara menghitung komponen yang dapat dipasang dan memeriksa apakah runtime mendukung kemampuan anchor terikat entity.
// 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 kode contoh xrEnumerateSpatialAnchorAttachableComponentsANDROID .