XR_ANDROID_spatial_entity_bound_anchor
سلسلة الاسم
XR_ANDROID_spatial_entity_bound_anchor
نوع الإضافة
إضافة مثيل
رقم الإضافة المسجَّل
791
المراجعة
2
حالة التصديق
لم تتم المصادقة
الاعتماديات على الإضافات والإصدارات
XR_EXT_spatial_anchor
تاريخ آخر تعديل
2025-08-18
حالة عنوان IP
ما مِن مطالبات معروفة بملكية الملكية الفكرية.
المساهمون
"يوشينغ تشانغ"، 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، 2018-08-18 (YuSheng Chang)
- الوصف الأوّلي للإضافة
المراجعة 2، 16-12-2025 (Kyle Chen)
- إضافة لغة أكثر توجيهًا إلى سلوكيات معيّنة لواجهة برمجة التطبيقات
- أضِف الرمز البرمجي النموذجي الخاص بـ xrEnumerateSpatialAnchorAttachableComponentsANDROID .