XR_ANDROID_spatial_entity_bound_anchor
Name String
XR_ANDROID_spatial_entity_bound_anchor
نوع الإضافة
إضافة مثيل
رقم الإضافة المسجَّل
791
المراجعة
2
حالة التصديق
لم تتم المصادقة عليها
الاعتماد على الإضافات والإصدارات
XR_EXT_spatial_anchor
تاريخ آخر تعديل
2025-08-18
حالة الملكية الفكرية
ما مِن مطالبات معروفة بشأن الملكية الفكرية.
المساهمون
يو شينغ تشانغ، Google
كايل تشن، Google
نيهاف جاين، Google
ليفانا تشن، Google
سبنسر كوين، 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 . -
systemIdهوXrSystemIdالذي سيتم تعداد مخازن الثبات المكاني الخاصة به. -
attachableComponentCapacityInputهي سعة مصفوفةattachableComponents، أو 0 للإشارة إلى طلب استرداد السعة المطلوبة. -
attachableComponentCountOutputهو عدد المكوّنات القابلة للإرفاق، أو السعة المطلوبة في حال عدم كفايةattachableComponentCapacityInput. -
attachableComponentsهي مصفوفة من XrSpatialComponentTypeEXT . يمكن أن تكون القيمةNULLإذا كانت قيمةattachableComponentCapacityInputهي 0. - يُرجى الاطّلاع على فصل مَعلمات حجم ذاكرة التخزين المؤقت للحصول على وصف تفصيلي لاسترداد حجم
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;
أوصاف الأعضاء
-
typeهو XrStructureType لهذه البنية. -
nextهوNULLأو مؤشر إلى البنية التالية في سلسلة البنى. -
parentIdهيXrSpatialEntityIdEXTالكيان الذي سيتم ربط نقطة الارتساء به.
يجب أن يضمن وقت التشغيل أنّ المسافة بين الكيان الرئيسي والمرساة متسقة دائمًا، حيث تكون المسافة هي وضعية المرساة إلى أقرب سطح للكيان الرئيسي على طول السطح العادي. يتم تعديل وضعية نقطة الارتساء استنادًا إلى موضع الكيان الأصلي والمسافة إلى سطح الكيان الأصلي بغض النظر عن عدد المكوّنات القابلة للإرفاق التي يتضمّنها الكيان الأصلي.
يجب أن يعرض وقت التشغيل XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT من xrCreateSpatialAnchorEXT إذا لم يكن XrSpatialAnchorParentANDROID ::parentId معرّفًا صالحًا لـ xrCreateSpatialAnchorEXT :: spatialContext .
يجب أن يعرض وقت التشغيل XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID من xrCreateSpatialAnchorEXT إذا لم يكن أي من المكوّنات التي تم تعدادها بواسطة xrEnumerateSpatialAnchorAttachableComponentsANDROID موجودًا في الكيان الأصلي.
الاستخدام الصالح (ضمني)
- يجب تفعيل إضافة
XR_ANDROID_spatial_entity_bound_anchorقبل استخدام XrSpatialAnchorParentANDROID - يجب أن يكون
typeXR_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.
// ...
الأوامر الجديدة
منشآت جديدة
ثوابت تعداد جديدة
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
المشاكل
سجلّ الإصدارات
المراجعة 1، بتاريخ 18 أغسطس 2025 (يو شينغ تشانغ)
- وصف الإضافة الأوّلي
الإصدار 2، 16 ديسمبر 2025 (كايل تشن)
- إضافة لغة أكثر توجيهًا إلى سلوكيات معيّنة لواجهة برمجة التطبيقات
- أضِف نموذج الرمز البرمجي xrEnumerateSpatialAnchorAttachableComponentsANDROID .