XR_ANDROID_spatial_entity_bound_anchor
رشته نام
XR_ANDROID_spatial_entity_bound_anchor
نوع افزونه
افزونه نمونه
شماره داخلی ثبت شده
۷۹۱
بازنگری
۲
وضعیت تصویب
تصویب نشده
وابستگیهای افزونه و نسخه
XR_EXT_spatial_anchor
آخرین تاریخ اصلاح
۲۰۲۵-۰۸-۱۸
وضعیت آیپی
هیچ ادعای مالکیت معنوی شناختهشدهای وجود ندارد.
مشارکتکنندگان
یوشنگ چانگ، گوگل
کایل چن، گوگل
نیهاو جین، گوگل
لوانا چن، گوگل
اسپنسر کوئین، گوگل
نمای کلی
این افزونه به برنامهها اجازه میدهد تا لنگرهایی (anchors) ایجاد کرده و به موجودیتهای مکانی (spatial entity) متصل کنند، که در این افزونه به آنها «لنگرهای وابسته به موجودیت» (entity-bound anchors) گفته میشود.
یک لنگرِ وابسته به موجودیت، به عنوان یک موجودیت مکانی با (یا «دارای») کامپوننت 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 است. -
systemIdهمانXrSystemIdاست که حافظههای ماندگاری مکانی آن شمارش خواهند شد. -
attachableComponentCapacityInputظرفیت آرایهattachableComponentsاست، یا 0 برای نشان دادن درخواست بازیابی ظرفیت مورد نیاز. -
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_UNSUPPORTED -
XR_ERROR_HANDLE_INVALID -
XR_ERROR_INSTANCE_LOST -
XR_ERROR_RUNTIME_FAILURE -
XR_ERROR_SIZE_INSUFFICIENT -
XR_ERROR_SYSTEM_INVALID -
XR_ERROR_VALIDATION_FAILURE
ایجاد یک لنگر وابسته به موجودیت مکانی
برنامهها از تابع xrCreateSpatialAnchorEXT برای ایجاد یک anchor استفاده میکنند. اگر برنامهای بخواهد یک anchor وابسته به entity ایجاد کند که به یک موجودیت مکانی متصل است، میتواند هنگام فراخوانی تابع xrCreateSpatialAnchorEXT ، یک ساختار XrSpatialAnchorParentANDROID را به اشارهگر بعدی ساختار XrSpatialAnchorCreateInfoEXT زنجیر کند.
ساختار XrSpatialAnchorParentANDROID به صورت زیر تعریف میشود:
typedef struct XrSpatialAnchorParentANDROID {
XrStructureType type;
const void* next;
XrSpatialEntityIdEXT parentId;
} XrSpatialAnchorParentANDROID;
توضیحات اعضا
-
typeنوع XrStructureType این ساختار است. -
nextNULLیا اشارهگری به ساختار بعدی در یک زنجیره ساختار است. -
parentId،XrSpatialEntityIdEXTمربوط به موجودیتی است که anchor به آن متصل خواهد شد.
زمان اجرا باید تضمین کند که فاصله بین موجودیت والد و لنگر همیشه ثابت باشد، که در آن فاصله، موقعیت لنگر تا نزدیکترین سطح موجودیت والد در امتداد خط عمود بر سطح است. موقعیت لنگر بر اساس موقعیت موجودیت والد و فاصله تا سطح موجودیت والد، صرف نظر از تعداد اجزای قابل اتصال موجودیت والد، بهروزرسانی میشود.
اگر 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یا یک اشارهگر معتبر به ساختار بعدی در یک زنجیره ساختار باشد.
کد مثال
ایجاد لنگر وابسته به موجودیت مکانی
کد مثال زیر نحوه ایجاد یک anchor متصل به entity و اتصال آن به یک موجودیت ردیابی صفحه مکانی را نشان میدهد.
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
// ...
}
دریافت موقعیت لنگر وابسته به موجودیت و شناسه موجودیت والد
کد مثال زیر نحوه دریافت موقعیت یک anchor متصل به entity و شناسه موجودیت والد آن را نشان میدهد.
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
// ...
}
شمارش اجزای قابل اتصال و بررسی قابلیت اتصال به موجودیت
کد مثال زیر نحوه شمارش اجزای قابل اتصال و بررسی اینکه آیا زمان اجرا از قابلیت اتصال به entity bound پشتیبانی میکند یا خیر را نشان میدهد.
// 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.
// ...
دستورات جدید
سازههای جدید
ثابتهای شمارشی جدید
-
XR_ANDROID_SPATIAL_ENTITY_BOUND_ANCHOR_EXTENSION_NAME -
XR_ANDROID_spatial_entity_bound_anchor_SPEC_VERSION بسط XrResult :
-
XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID
-
گسترش XrStructureType :
-
XR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROID
-
مسائل
تاریخچه نسخه
ویرایش 1، 18-08-2025 (YuSheng Chang)
- توضیحات اولیه افزونه
نسخه ۲، ۲۰۲۵-۱۲-۱۶ (کایل چن)
- زبان تجویزی بیشتری به رفتارهای خاص API اضافه کنید.
- کد نمونه xrEnumerateSpatialAnchorAttachableComponentsANDROID را اضافه کنید.