XR_ANDROID_spatial_entity_bound_anchor
رشته نام
XR_ANDROID_spatial_entity_bound_anchor
نوع افزونه
افزونه نمونه
شماره داخلی ثبتشده
791
بازبینی
2
وضعیت تصویب
تصویبنشده
وابستگیهای افزونه و نسخه
XR_EXT_spatial_anchor
تاریخ آخرین تغییر
2025-08-18
وضعیت IP
هیچ ادعای مالکیت فکری شناختهشدهای وجود ندارد.
همیاران
YuSheng Chang، Google
Kyle Chen، Google
Nihav Jain، Google
Levana Chen، Google
Spencer Quin، Google
نمای کلی
این افزونه به برنامهها اجازه میدهد لنگر ایجاد کنند و آنها را به نهادهای فضایی متصل کنند که در این افزونه «لنگرهای محدود به نهاد» نامیده میشوند.
لنگر محدود به نهاد بهعنوان نهادی فضایی با (یا «که دارای») مؤلفه XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT و مؤلفه XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT نشان داده میشود. مؤلفه XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT، XrSpatialEntityIdEXT نهاد اصلی را که لنگر به آن متصل است ذخیره میکند.
حالت لنگر محدود به نهاد همیشه با یک انحراف ثابت از نهاد ولی آن نشان داده میشود که بهعنوان «پایه» لنگر درنظر گرفته میشود. برای مثال، تصور کنید کاربری یک قاب عکس مجازی دارد که به دیوار متصل است، کاربر از یک لنگر محدود به موجودیت برای نمایش قاب عکس مجازی استفاده میکند و آن را به موجودیت دیوار متصل میکند. با این کار، موقعیت نسبی بین دیوار و قاب عکس همیشه ثابت میماند، زیرا تخمینهای ردیابی دیوار فیزیکی بهبود مییابد.
پشتیبانی زمان اجرا
زمان اجرا باید حداقل از یک افزونه ردیابی فضایی، مثلاً XR_EXT_spatial_plane_tracking، پشتیبانی کند. اگر زمان اجرا از لنگر محدودشده به نهاد فضایی پشتیبانی کند، باید با شمارش تابع xrEnumerateSpatialAnchorAttachableComponentsANDROID حداقل یک مؤلفه قابلپیوست ارائه دهد. برنامه میتواند مؤلفههای قابلاتصال را بااستفاده از xrEnumerateSpatialAnchorAttachableComponentsANDROID شمارش کند.
تابع xrEnumerateSpatialAnchorAttachableComponentsANDROID بهصورت زیر تعریف میشود:
XrResult xrEnumerateSpatialAnchorAttachableComponentsANDROID(
XrInstance instance,
XrSystemId systemId,
uint32_t attachableComponentCapacityInput,
uint32_t* attachableComponentCountOutput,
XrSpatialComponentTypeEXT* attachableComponents);
شرح پارامترها
-
instanceدستهای برای XrInstance است. systemIdXrSystemIdاست که فروشگاههای پایداری فضایی آن شمارش خواهد شد.attachableComponentCapacityInputظرفیت آرایهattachableComponentsاست، یا ۰ برای نشان دادن درخواست بازیابی ظرفیت موردنیاز.-
attachableComponentCountOutputتعداد مؤلفههای قابلپیوست است، یا ظرفیت موردنیاز درصورتیکهattachableComponentCapacityInputکافی نباشد. -
attachableComponentsآرایهای از XrSpatialComponentTypeEXT است. اگرattachableComponentCapacityInputبرابر با ۰ باشد، میتواندNULLباشد. - برای شرح دقیق بازیابی اندازه
attachableComponentsموردنیاز، فصل پارامترهای اندازه میانگیر را ببینید.
زمانهای اجرا باید همیشه محتوای میانگیر یکسانی را از این شمارش برای systemId دادهشده در طول عمر نمونه برگردانند.
استفاده معتبر (ضمنی)
- افزونه
XR_ANDROID_spatial_entity_bound_anchorباید قبلاز فراخوانی xrEnumerateSpatialAnchorAttachableComponentsANDROID فعال شود -
instanceباید شناسه XrInstance معتبری باشد -
attachableComponentCountOutputباید اشارهگری به مقدارuint32_tباشد - اگر
attachableComponentCapacityInputبرابر با0نباشد،attachableComponentsباید اشارهگری به آرایهای از مقادیرattachableComponentCapacityInputXrSpatialComponentTypeEXT باشد
کدهای برگشتی
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_RUNTIME_FAILUREXR_ERROR_SIZE_INSUFFICIENTXR_ERROR_SYSTEM_INVALIDXR_ERROR_VALIDATION_FAILURE
درحال ایجاد لنگر محدود به موجودیت فضایی
برنامهها از تابع xrCreateSpatialAnchorEXT برای ایجاد لنگر استفاده میکنند. اگر برنامهای بخواهد لنگر محدود به نهاد ایجاد کند که به نهاد فضایی متصل باشد، میتواند ساختار XrSpatialAnchorParentANDROID را به اشارهگر بعدی ساختار XrSpatialAnchorCreateInfoEXT هنگام فراخوانی تابع xrCreateSpatialAnchorEXT زنجیر کند.
ساختار XrSpatialAnchorParentANDROID بهصورت زیر تعریف میشود:
typedef struct XrSpatialAnchorParentANDROID {
XrStructureType type;
const void* next;
XrSpatialEntityIdEXT parentId;
} XrSpatialAnchorParentANDROID;
توضیحات عضو
typeXrStructureType این ساختار است.-
nextبرابر باNULLیا اشارهگری به ساختار بعدی در زنجیره ساختار است. -
parentIdعبارت است ازXrSpatialEntityIdEXTنهادی که لنگر به آن متصل خواهد شد.
زمان اجرا باید تضمین کند که فاصله بین موجودیت ولی و لنگر همیشه ثابت است، که در آن فاصله عبارت است از حالت لنگر تا نزدیکترین سطح موجودیت ولی در امتداد سطح نرمال. وضعیت لنگر براساس موقعیت نهاد ولی و فاصله تا سطح نهاد ولی بهروز میشود، صرفنظر از اینکه نهاد ولی چند مؤلفه قابلاتصال دارد.
اگر XrSpatialAnchorParentANDROID ::parentId شناسه معتبری برای xrCreateSpatialAnchorEXT :: spatialContext نباشد، زمان اجرا باید XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT را از xrCreateSpatialAnchorEXT برگرداند.
اگر هیچکدام از مؤلفههای شمارششده توسط xrEnumerateSpatialAnchorAttachableComponentsANDROID در موجودیت والد نباشند، زمان اجرا باید XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID را از xrCreateSpatialAnchorEXT برگرداند.
استفاده معتبر (ضمنی)
- افزونه
XR_ANDROID_spatial_entity_bound_anchorباید قبلاز استفاده از XrSpatialAnchorParentANDROID فعال شود -
typeبایدXR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROIDباشد -
nextبایدNULLیا اشارهگر معتبری به ساختار بعدی در زنجیره ساختار باشد
کد نمونه
ایجاد لنگر محدود به موجودیت فضایی
کد نمونه زیر نشان میدهد که چگونه میتوان یک لنگر محدود به موجودیت ایجاد کرد و آن را به یک موجودیت ردیابی صفحه فضایی متصل کرد.
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
// ...
}
دریافت حالت لنگر محدود به نهاد و شناسه نهاد والد
کد نمونه زیر نحوه دریافت وضعیت لنگر محدود به موجودیت و شناسه موجودیت اصلی آن را نشان میدهد.
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
// ...
}
شمارش مؤلفههای قابلاتصال و بررسی قابلیت لنگر محدود به نهاد
کد نمونه زیر نحوه شمارش مؤلفههای قابلاتصال و بررسی اینکه آیا زمان اجرا از قابلیت لنگر محدود به نهاد پشتیبانی میکند یا نه را نشان میدهد.
// 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.
// ...
فرمانهای جدید
سازههای جدید
درحال گسترش دادن XrSpatialAnchorCreateInfoEXT :
ثابتهای شمارشی جدید
XR_ANDROID_SPATIAL_ENTITY_BOUND_ANCHOR_EXTENSION_NAMEXR_ANDROID_spatial_entity_bound_anchor_SPEC_VERSIONدرحال گسترش دادن XrResult :
XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID
درحال گسترش دادن XrStructureType :
XR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROID
مشکلات
سابقه نسخه
بازبینی ۱، ۲۰۲۵-۰۸-۱۸ (YuSheng Chang)
- توضیحات اولیه افزونه.
بازبینی ۲، ۲۰۲۵/۱۲/۱۶ (کایل چن)
- افزودن زبان تجویزی بیشتر به برخیاز رفتارهای API.
- کد نمونه xrEnumerateSpatialAnchorAttachableComponentsANDROID را اضافه کنید.