XR_EXT_spatial_anchor
מחרוזת שם
XR_EXT_spatial_anchor
סוג התוסף
הרחבת המכונה
מספר שלוחה רשום
763
Revision
1
סטטוס האישור
אושר
תלות בתוסף ובגרסה
XR_EXT_spatial_entity
שותפים ביצירת התוכן
Nihav Jain, Google
Natalie Fleury, Meta
Yuichi Taguchi, Meta
Ron Bessems, Meta
Yin Li, Microsoft
Jimmy Alamparambil, ByteDance
Zhipeng Liu, ByteDance
Jun Yan, ByteDance
סקירה כללית
התוסף הזה מבוסס על XR_EXT_spatial_entity ומאפשר לאפליקציות ליצור עוגנים מרחביים, שהם נקודות שרירותיות בסביבה הפיזית של המשתמש, שזמן הריצה יעקוב אחריהן. ה-runtime צריך להתאים את המיקום והכיוון של נקודת המוצא של העוגן לאורך זמן לפי הצורך, בלי קשר לכל המרחבים והעוגנים האחרים, כדי לוודא שהמיפוי המקורי שלו לעולם האמיתי נשמר.
עוגן שעוקב אחרי מיקום וכיוון נתונים בתוך XrSpatialContextEXT מיוצג כישות מרחבית עם הרכיב XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT (או 'שיש לה' את הרכיב 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_EXT_spatial_anchorלפני שמשתמשים ב-XrSpatialCapabilityConfigurationAnchorEXT -
typeחייב להיותXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT -
nextחייב להיותNULLאו מצביע תקין אל המבנה הבא בשרשרת המבנים -
capabilityחייב להיות ערך תקין של XrSpatialCapabilityEXT -
enabledComponentsmust be a pointer to an array ofenabledComponentCountvalid XrSpatialComponentTypeEXT values - הפרמטר
enabledComponentCountחייב להיות גדול מ-0
רכיבים מובטחים
סביבת ריצה שתומכת ב-XR_SPATIAL_CAPABILITY_ANCHOR_EXT חייבת לספק את הרכיבים המרחביים הבאים כרכיבים מובטחים של כל הישויות שנוצרו או התגלו על ידי היכולת הזו, וחייבת למנות אותם ב-xrEnumerateSpatialCapabilityComponentTypesEXT :
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
רכיב העוגן
נתוני רכיבים
ה-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);
תיאורי הפרמטרים
-
spatialContextהוא XrSpatialContextEXT שנוצר קודם באמצעות xrCreateSpatialContextAsyncEXT . -
createInfoהוא מצביע אל XrSpatialAnchorCreateInfoEXT . -
anchorEntityIdהוא מצביע ל-XrSpatialEntityIdEXTשבו מוחזר המזהה של ישות העוגן. -
anchorEntityהוא מצביע אל XrSpatialEntityEXT שבו מוחזר הכינוי של ישות העוגן.
האפליקציה יכולה ליצור עוגן מרחבי באמצעות 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 ב-snapshot שנוצר באמצעות xrCreateSpatialDiscoverySnapshotAsyncEXT עבור spatialContext אם העוגן תואם לקריטריוני הגילוי שמוגדרים ב-XrSpatialDiscoverySnapshotCreateInfoEXT . יכול להיות שגם העוגן החדש שנוצר יהיה גלוי בהקשרים מרחביים אחרים שהוגדרו עם XR_SPATIAL_CAPABILITY_ANCHOR_EXT, אבל עם XrSpatialEntityIdEXT שונה, כי XrSpatialEntityIdEXT מסוים הוא ייחודי ל-XrSpatialContextEXT שלו .
שימוש תקף (משתמע)
- צריך להפעיל את התוסף
XR_EXT_spatial_anchorלפני שמתקשרים אל xrCreateSpatialAnchorEXT -
spatialContextmust be a valid XrSpatialContextEXT handle -
createInfomust be a pointer to a valid XrSpatialAnchorCreateInfoEXT structure -
anchorEntityIdחייב להיות מצביע לערךXrSpatialEntityIdEXT -
anchorEntitymust be a pointer to an XrSpatialEntityEXT handle
קודי החזרה
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_LIMIT_REACHEDXR_ERROR_OUT_OF_MEMORYXR_ERROR_POSE_INVALIDXR_ERROR_RUNTIME_FAILUREXR_ERROR_SESSION_LOSTXR_ERROR_TIME_INVALIDXR_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הוא המיקום של ישות העוגן.
שימוש תקף (משתמע)
- התוסף
XR_EXT_spatial_anchorחייב להיות מופעל לפני שמשתמשים ב-XrSpatialAnchorCreateInfoEXT -
typeחייב להיותXR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT -
nextחייב להיותNULLאו מצביע תקין למבנה הבא בשרשרת מבנים . מידע נוסף: XrSpatialAnchorParentANDROID -
baseSpaceחייב להיות כינוי תקין ב-XrSpace
Query Anchor 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));
פקודות חדשות
מבנים חדשים
- XrSpatialAnchorCreateInfoEXT
- XrSpatialCapabilityConfigurationAnchorEXT
הרחבה של XrSpatialComponentDataQueryResultEXT :
New Enum Constants
XR_EXT_SPATIAL_ANCHOR_EXTENSION_NAMEXR_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_EXTXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXTXR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT
בעיות
למה הפונקציה xrCreateSpatialAnchorEXT מחזירה מזהה ישות וגם נקודת אחיזה של ישות?
- טופל
- תשובה: יכול להיות שהפונקציה xrCreateSpatialAnchorEXT סיפקה רק את מזהה הישות כפלט, ואפליקציות יכלו ליצור נקודת אחיזה של ישות עבור המזהה הזה באמצעות xrCreateSpatialEntityFromIdEXT . עם זאת, בהתחשב בשימוש הטיפוסי בעוגן שבו האפליקציות שולחות שאילתה לגבי מיקום העוגן בכל פריים, הוא הופך למועמד טוב לשימוש ב'עדכון תמונת מצב', שדורש ידיות של ישויות כקלט. כדי להתמודד עם תרחיש השימוש האופייני הזה, הפונקציה xrCreateSpatialAnchorEXT מבצעת את הפונקציה xrCreateSpatialEntityFromIdEXT בשם האפליקציה ומספקת לה את ה-handle של הישות לשימוש עם הפונקציה xrCreateSpatialUpdateSnapshotEXT .
היסטוריית הגרסאות
גרסה 1, 10 ביולי 2024 (Nihav Jain, Google)
- תיאור ראשוני של התוסף