XR_EXT_spatial_anchor

Name String

XR_EXT_spatial_anchor

نوع الإضافة

إضافة مثيل

رقم الإضافة المسجَّل

763

المراجعة

1

حالة التصديق

تمت المصادقة عليه

الاعتماد على الإضافات والإصدارات

XR_EXT_spatial_entity

المساهمون

"نيهاف جاين"، Google
"ناتالي فلوري"، Meta
"يويتشي تاغوتشي"، Meta
"رون بيسمز"، Meta
"يين لي"، Microsoft
"جيمي ألامبارامبيل"، ByteDance
"تشيبينغ ليو"، ByteDance
"جون يان"، ByteDance

نظرة عامة

تستند هذه الإضافة إلى XR_EXT_spatial_entity وتسمح للتطبيقات بإنشاء نقاط ارتساء مكانية، وهي نقاط عشوائية في البيئة المادية للمستخدم يتم تتبُّعها بعد ذلك من خلال بيئة التشغيل. يجب أن تعدّل بيئة التشغيل بعد ذلك موضع نقطة الارتكاز واتجاهها بمرور الوقت حسب الحاجة، وبشكل مستقل عن جميع المساحات ونقاط الارتكاز الأخرى، لضمان الحفاظ على ربطها الأصلي بالعالم الحقيقي.

يتم تمثيل نقطة الارتساء التي تتتبّع موضعًا واتجاهًا معيّنَين ضمن XrSpatialContextEXT ككيان مكاني يتضمّن المكوّن XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT.

مزايا استخدام نقاط الارتكاز

بما أنّ فهم بيئة التشغيل للبيئة المادية للمستخدم يتغيّر طوال مدة استخدام XrSpatialContextEXT، قد تبدو العناصر الافتراضية وكأنّها تبتعد عن المكان الذي وضعها فيه التطبيق، ما يؤثر في واقعية التطبيق وجودة تجربة المستخدم. من خلال إنشاء نقطة ارتساء بالقرب من مكان وضع عنصر افتراضي، ثم عرض هذا العنصر الافتراضي دائمًا بالنسبة إلى نقطة الارتساء الخاصة به، يمكن للتطبيق التأكّد من أنّ كل عنصر افتراضي يظهر في الموضع والاتجاه نفسهما في البيئة المادية. وعلى عكس بعض المساحات المرجعية، لا تتأثر نقاط الارتساء بإعادة التوسيط على مستوى النظام.

دعم وقت التشغيل

إذا كان وقت التشغيل يتيح استخدام نقاط الارتكاز المكانية، يجب أن يشير إلى ذلك من خلال تعداد XR_SPATIAL_CAPABILITY_ANCHOR_EXT في xrEnumerateSpatialCapabilitiesEXT .

الإعداد

يتم تعريف بنية XrSpatialCapabilityConfigurationAnchorEXT على النحو التالي:

typedef struct XrSpatialCapabilityConfigurationAnchorEXT {
    XrStructureType                     type;
    const void*                         next;
    XrSpatialCapabilityEXT              capability;
    uint32_t                            enabledComponentCount;
    const XrSpatialComponentTypeEXT*    enabledComponents;
} XrSpatialCapabilityConfigurationAnchorEXT;

أوصاف الأعضاء

  • ‫type هو XrStructureType لهذه البنية.
  • ‫next هو NULL أو مؤشر إلى البنية التالية في سلسلة البنى.
  • capability هو XrSpatialCapabilityEXT .
  • ‫enabledComponentCount هو uint32_t يصف عدد العناصر في مصفوفة enabledComponents.
  • ‫enabledComponents هو مؤشر إلى مصفوفة من XrSpatialComponentTypeEXT .

يمكن للتطبيقات تفعيل الإمكانية المكانية XR_SPATIAL_CAPABILITY_ANCHOR_EXT من خلال تضمين مؤشر إلى بنية XrSpatialCapabilityConfigurationAnchorEXT في XrSpatialContextCreateInfoEXT :: capabilityConfigs .

يجب أن يعرض وقت التشغيل XR_ERROR_VALIDATION_FAILURE إذا لم يكن capability هو XR_SPATIAL_CAPABILITY_ANCHOR_EXT .

الاستخدام الصالح (ضمني)

المكوّنات المضمونة

يجب أن يوفّر وقت التشغيل الذي يتيح استخدام XR_SPATIAL_CAPABILITY_ANCHOR_EXT المكوّنات المكانية التالية كمكوّنات مضمونة لجميع الكيانات التي تم إنشاؤها أو اكتشافها من خلال هذه الإمكانية، ويجب تعدادها في xrEnumerateSpatialCapabilityComponentTypesEXT :

  • XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT

مكوّن Anchor

بيانات المكوّن

يستخدم XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT XrPosef لبياناته التي توفّر موضع نقطة الارتساء واتجاهها.

بنية قائمة المكوّنات لبيانات طلب البحث

يتم تحديد بنية XrSpatialComponentAnchorListEXT على النحو التالي:

typedef struct XrSpatialComponentAnchorListEXT {
    XrStructureType    type;
    void*              next;
    uint32_t           locationCount;
    XrPosef*           locations;
} XrSpatialComponentAnchorListEXT;

أوصاف الأعضاء

  • ‫type هو XrStructureType لهذه البنية.
  • ‫next هو NULL أو مؤشر إلى البنية التالية في سلسلة البنى.
  • ‫locationCount هو uint32_t يصف عدد العناصر في مصفوفة locations.
  • ‫locations هو مصفوفة من XrPosef .

يجب أن يعرض وقت التشغيل XR_ERROR_VALIDATION_FAILURE من xrQuerySpatialComponentDataEXT إذا كان XrSpatialComponentAnchorListEXT في السلسلة XrSpatialComponentDataQueryResultEXT :: next ولكن لم يتم تضمين XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT في XrSpatialComponentDataQueryConditionEXT :: componentTypes .

يجب أن يعرض وقت التشغيل XR_ERROR_SIZE_INSUFFICIENT من xrQuerySpatialComponentDataEXT إذا كان locationCount أقل من XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput .

الاستخدام الصالح (ضمني)

  • يجب تفعيل إضافة XR_EXT_spatial_anchor قبل استخدام XrSpatialComponentAnchorListEXT
  • يجب أن يكون type XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT
  • next يجب أن تكون NULL أو مؤشرًا صالحًا إلى البنية التالية في سلسلة البنية
  • يجب أن يكون locations مؤشرًا إلى مصفوفة من هياكل locationCount XrPosef
  • يجب أن تكون المَعلمة locationCount أكبر من 0
الإعداد

إذا تم تعداد XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT في XrSpatialCapabilityComponentTypesEXT :: componentTypes لبعض الإمكانات، يمكن للتطبيق تفعيلها من خلال تضمين التعداد في قائمة XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents للبنية المشتقة من XrSpatialCapabilityConfigurationBaseHeaderEXT للإمكانية التي تتيح هذا المكوّن.

لا يتطلّب هذا المكوّن أي إعدادات خاصة ليتم تضمينه في سلسلة XrSpatialCapabilityConfigurationBaseHeaderEXT :: next.

إنشاء نقطة تثبيت مكانية

يتم تعريف الدالة xrCreateSpatialAnchorEXT على النحو التالي:

XrResult xrCreateSpatialAnchorEXT(
    XrSpatialContextEXT                         spatialContext,
    const XrSpatialAnchorCreateInfoEXT*         createInfo,
    XrSpatialEntityIdEXT*                       anchorEntityId,
    XrSpatialEntityEXT*                         anchorEntity);

أوصاف المَعلمات

يمكن للتطبيق إنشاء نقطة تثبيت مكانية باستخدام xrCreateSpatialAnchorEXT .

للحصول على بيانات مكوّنات محدَّثة لارتكاز معيّن، أدخِل القيمة التي تم ملؤها في anchorEntity في XrSpatialUpdateSnapshotCreateInfoEXT :: entities عند إنشاء لقطة. يمكن للتطبيق استخدام anchorEntityId لتحديد هذا الارتساء بشكل فريد في مصفوفة XrSpatialComponentDataQueryResultEXT :: entityIds عند استخدام xrQuerySpatialComponentDataEXT .

يجب أن يعرض وقت التشغيل XR_ERROR_VALIDATION_FAILURE من xrCreateSpatialAnchorEXT إذا لم يتم ضبط XR_SPATIAL_CAPABILITY_ANCHOR_EXT لـ spatialContext . يمكنك الاطّلاع على الإعدادات لمعرفة كيفية ضبط XrSpatialContextEXT لإمكانية XR_SPATIAL_CAPABILITY_ANCHOR_EXT.

يكون الارتساء الذي يمثّله anchorEntity صالحًا فقط طوال مدة صلاحية spatialContext، أو إلى أن يستدعي التطبيق xrDestroySpatialEntityEXT عليه، أيهما أقرب. قد توفّر الإضافات الأخرى وظائف للاحتفاظ بهذا الارتساء الذي تم إنشاؤه حديثًا في جلسات XrSession متعددة أو لمشاركته عبر حدود العمليات مع تطبيقات أخرى.

يجب أن يكون الارتساء الذي تم إنشاؤه حديثًا قابلاً للاكتشاف في سياقه المكاني الرئيسي إلى أن يتم تدميره. يعني ذلك أنّ بيئة التشغيل يجب أن تتضمّن anchorEntityId في اللقطة التي تم إنشاؤها باستخدام xrCreateSpatialDiscoverySnapshotAsyncEXT لـ spatialContext إذا كان الارتساء يتطابق مع معايير الاكتشاف المحدّدة في XrSpatialDiscoverySnapshotCreateInfoEXT . قد يكون أيضًا بالإمكان اكتشاف نقطة الارتساء التي تم إنشاؤها حديثًا في سياقات مكانية أخرى تم ضبطها باستخدام XR_SPATIAL_CAPABILITY_ANCHOR_EXT، ولكن باستخدام XrSpatialEntityIdEXT مختلف لأنّ XrSpatialEntityIdEXT معيّن يكون فريدًا في XrSpatialContextEXT الخاص به.

الاستخدام الصالح (ضمني)

  • يجب تفعيل الإضافة XR_EXT_spatial_anchor قبل استدعاء xrCreateSpatialAnchorEXT
  • يجب أن يكون spatialContext مؤشرًا صالحًا لـ XrSpatialContextEXT
  • createInfo يجب أن يكون مؤشرًا إلى بنية XrSpatialAnchorCreateInfoEXT صالحة
  • يجب أن يكون anchorEntityId مؤشرًا إلى قيمة XrSpatialEntityIdEXT
  • يجب أن يكون anchorEntity مؤشرًا إلى اسم معرِّف XrSpatialEntityEXT

رموز الإرجاع

Success

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

تعذّر الإجراء

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_LIMIT_REACHED
  • XR_ERROR_OUT_OF_MEMORY
  • XR_ERROR_POSE_INVALID
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_TIME_INVALID
  • XR_ERROR_VALIDATION_FAILURE
  • ‫XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID (في حال تفعيل XR_ANDROID_spatial_entity_bound_anchor)
  • ‫XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT (في حال تفعيل XR_ANDROID_spatial_entity_bound_anchor)

يتم تحديد بنية XrSpatialAnchorCreateInfoEXT على النحو التالي:

typedef struct XrSpatialAnchorCreateInfoEXT {
    XrStructureType    type;
    const void*        next;
    XrSpace            baseSpace;
    XrTime             time;
    XrPosef            pose;
} XrSpatialAnchorCreateInfoEXT;

أوصاف الأعضاء

  • ‫type هو XrStructureType لهذه البنية.
  • ‫next هو NULL أو مؤشر إلى البنية التالية في سلسلة البنى.
  • ‫baseSpace هي XrSpace التي يتم تطبيق pose فيها.
  • ‫time هي XrTime التي تقع فيها baseSpace (ويتم تطبيق pose).
  • ‫pose هو الموقع الجغرافي للجهة الأساسية.

الاستخدام الصالح (ضمني)

طلب البحث عن وضعية الارتساء

بعد إنشاء نقطة الارتكاز، يجب أن يعدّل وقت التشغيل موضعها واتجاهها بمرور الوقت بالنسبة إلى المساحات الأخرى من أجل الحفاظ على أفضل محاذاة ممكنة لموقعها الأصلي في العالم الحقيقي، حتى إذا غيّر ذلك علاقة نقطة الارتكاز بالبنية الأصلية XrSpatialAnchorCreateInfoEXT :: baseSpace المستخدَمة لإعدادها.

يمكن للتطبيق استخدام xrCreateSpatialUpdateSnapshotEXT مع XrSpatialEntityEXT الخاص بنقطة الارتكاز لإنشاء XrSpatialSnapshotEXT جديد، ثم طلب البحث عن مكوّن XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT من تلك اللقطة باستخدام xrQuerySpatialComponentDataEXT . يمكن للتطبيق إضافة XrSpatialComponentAnchorListEXT إلى XrSpatialComponentDataQueryResultEXT :: next لاسترداد أحدث بيانات الموقع الجغرافي لنقاط الارتكاز.

قد تضبط بيئة التشغيل حالة تتبُّع نقطة ارتساء تم إنشاؤها حديثًا على XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT . يجب أن يقرأ التطبيق حالة الكيان الثابت المقدَّمة في XrSpatialComponentDataQueryResultEXT :: entityStates وبيانات مكوّن الكيان الثابت فقط إذا كانت حالة التتبُّع هي XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT .

إرشادات لاستخدام نقاط الارتساء

  • يتم تعديل وضعية كل نقطة ارتساء بشكل مستقل عن أي نقطة ارتساء أو مساحة أخرى. قد تتحرك العناصر الافتراضية المثبّتة بشكل منفصل أو تدور بالنسبة إلى بعضها البعض، ما يؤدي إلى كسر التسلسل الهرمي المكاني في الحالات التي يُتوقع فيها أن تظل هذه العناصر الافتراضية في مكانها بالنسبة إلى بعضها البعض. في هذه الحالات، يجب أن يعيد التطبيق استخدام نقطة الارتكاز نفسها لجميع العناصر الافتراضية التي لا تتحرك بالنسبة إلى بعضها البعض.
  • يجب أن يتلف التطبيق أيّ مؤشرات XrSpatialEntityEXT للمثبّتات التي لم تعُد قيد الاستخدام من أجل إخلاء الموارد التي قد يستخدمها وقت التشغيل لتتبُّع هذه المثبّتات.

مثال على الشفرة

ضبط إمكانية الربط

يوضّح المثال التالي كيفية ضبط ميزة الارتساء عند إنشاء سياق مكاني.

// Create a spatial spatial context
XrSpatialContextEXT spatialContext{};
{

  std::vector<XrSpatialComponentTypeEXT> enabledComponents = {
    XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT,
  };

  XrSpatialCapabilityConfigurationAnchorEXT anchorConfig{XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT};
  anchorConfig.capability = XR_SPATIAL_CAPABILITY_ANCHOR_EXT;
  anchorConfig.enabledComponentCount = enabledComponents.size();
  anchorConfig.enabledComponents = enabledComponents.data();

  std::array<XrSpatialCapabilityConfigurationBaseHeaderEXT*, 1> capabilityConfigs = {
    reinterpret_cast<XrSpatialCapabilityConfigurationBaseHeaderEXT*>(&anchorConfig),
  };

  XrSpatialContextCreateInfoEXT spatialContextCreateInfo{XR_TYPE_SPATIAL_CONTEXT_CREATE_INFO_EXT};
  spatialContextCreateInfo.capabilityConfigCount = capabilityConfigs.size();
  spatialContextCreateInfo.capabilityConfigs = capabilityConfigs.data();
  XrFutureEXT createContextFuture;
  CHK_XR(xrCreateSpatialContextAsyncEXT(session, &spatialContextCreateInfo, &createContextFuture));

  waitUntilReady(createContextFuture);

  XrCreateSpatialContextCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_CONTEXT_COMPLETION_EXT};
  CHK_XR(xrCreateSpatialContextCompleteEXT(session, createContextFuture, &completion));
  if (completion.futureResult != XR_SUCCESS) {
    return;
  }

  spatialContext = completion.spatialContext;
}

// ...
// Create spatial anchors and get their latest pose in the frame loop.
// ...

CHK_XR(xrDestroySpatialContextEXT(spatialContext));

إنشاء نقطة تثبيت مكانية والحصول على موقعها الجغرافي

يوضّح المثال التالي كيفية إنشاء نقطة تثبيت مكانية والحصول على وضعيتها في كل لقطة.

XrSpatialAnchorCreateInfoEXT createInfo{XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT};
createInfo.baseSpace = localSpace;
createInfo.time = predictedDisplayTime;
createInfo.pose = {{0, 0, 0, 1}, {1, 1, 1}};

XrSpatialEntityIdEXT spatialAnchorEntityId;
XrSpatialEntityEXT spatialAnchorEntity;
CHK_XR(xrCreateSpatialAnchorEXT(spatialContext, &createInfo, &spatialAnchorEntityId, &spatialAnchorEntity));

auto updateAnchorLocation = [&](XrTime time) {
  // We want to get updated data for all components of the entities, so skip specifying componentTypes.
  XrSpatialUpdateSnapshotCreateInfoEXT snapshotCreateInfo{XR_TYPE_SPATIAL_UPDATE_SNAPSHOT_CREATE_INFO_EXT};
  snapshotCreateInfo.entityCount = 1;
  snapshotCreateInfo.entities = &spatialAnchorEntity;
  snapshotCreateInfo.baseSpace = localSpace;
  snapshotCreateInfo.time = time;

  XrSpatialSnapshotEXT snapshot;
  CHK_XR(xrCreateSpatialUpdateSnapshotEXT(spatialContext, &snapshotCreateInfo, &snapshot));

  // Query for the entities that have the anchor component on them.
  std::array<XrSpatialComponentTypeEXT, 1> componentsToQuery {XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT};
  XrSpatialComponentDataQueryConditionEXT queryCond{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT};
  queryCond.componentTypeCount = componentsToQuery.size();
  queryCond.componentTypes = componentsToQuery.data();

  XrSpatialComponentDataQueryResultEXT queryResult{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{XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT};
  locationList.locationCount = locations.size();
  locationList.locations = locations.data();
  queryResult.next = &locationList;

  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].
    }
  }

  CHK_XR(xrDestroySpatialSnapshotEXT(snapshot));
};


while (1) {
  // ...
  // For every frame in frame loop
  // ...

  XrFrameState frameState;  // previously returned from xrWaitFrame
  const XrTime time = frameState.predictedDisplayTime;

  updateAnchorLocation(time);

  // ...
  // Finish frame loop
  // ...
}

CHK_XR(xrDestroySpatialEntityEXT(spatialAnchorEntity));

الأوامر الجديدة

منشآت جديدة

ثوابت تعداد جديدة

  • XR_EXT_SPATIAL_ANCHOR_EXTENSION_NAME
  • XR_EXT_spatial_anchor_SPEC_VERSION
  • توسيع XrSpatialCapabilityEXT :

    • XR_SPATIAL_CAPABILITY_ANCHOR_EXT
  • توسيع XrSpatialComponentTypeEXT :

    • XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
  • توسيع XrStructureType :

    • XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT
    • XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT
    • XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT

المشاكل

  • لماذا تُخرج الدالة xrCreateSpatialAnchorEXT رقم تعريف الكيان بالإضافة إلى مؤشر الكيان؟

    • تم الحلّ
    • الإجابة: كان من الممكن أن توفّر الدالة xrCreateSpatialAnchorEXT معرّف الكيان فقط كمخرجات، وكان بإمكان التطبيقات إنشاء معرّف كيان لهذا المعرّف باستخدام xrCreateSpatialEntityFromIdEXT . ومع ذلك، نظرًا للاستخدام المعتاد للمثبّت حيث تطلب التطبيقات وضعية المثبّت في كل إطار، يصبح مرشحًا جيدًا للاستخدام في "لقطة تحديث"، والتي تتطلب مقابض الكيانات كمدخلات. تحسُّبًا لحالة الاستخدام المعتادة هذه، تنفّذ الدالة xrCreateSpatialAnchorEXT الدالة xrCreateSpatialEntityFromIdEXT نيابةً عن التطبيق وتزوّده بمؤشر الكيان لاستخدامه مع الدالة xrCreateSpatialUpdateSnapshotEXT .

سجلّ الإصدارات

  • المراجعة 1، ‏10-07-2024 (نيهف جاين، Google)

    • الوصف الأولي للإضافة