XR_EXT_spatial_anchor
מחרוזת שם
XR_EXT_spatial_anchor
סוג התוסף
תוסף למכונה
מספר השלוחה הרשום
763
גרסה
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 ומאפשר לאפליקציות ליצור נקודות עיגון מרחביות, שהן נקודות שרירותיות בסביבה הפיזית של המשתמש, שאחריהן יתבצע מעקב על ידי סביבת זמן הריצה. לאחר מכן, סביבת זמן הריצה צריכה להתאים את המיקום והכיוון של מקור העוגן לאורך זמן לפי הצורך, ללא תלות בכל המרחבים והעוגנים האחרים, כדי לוודא שהוא שומר על המיפוי המקורי שלו לעולם האמיתי.
עוגן שעוקב אחרי מיקום וכיוון נתונים בתוך 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_EXT_spatial_anchorלפני שמשתמשים ב-XrSpatialCapabilityConfigurationAnchorEXT -
typeחייב להיותXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT -
nextחייב להיותNULLאו מצביע תקין למבנה הבא בשרשרת מבנים -
capabilityחייב להיות ערך XrSpatialCapabilityEXT תקין -
enabledComponentsחייב להיות מצביע למערך של ערכי XrSpatialComponentTypeEXT תקינים מסוגenabledComponentCount - הפרמטר
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חייב להיות מצביע למערך של מבניlocationCountXrPosef - הפרמטר
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 בתמונת המצב שנוצרה באמצעות xrCreateSpatialDiscoverySnapshotAsyncEXT עבור spatialContext אם נקודת העיגון תואמת לקריטריונים של הגילוי שהוגדרו ב-XrSpatialDiscoverySnapshotCreateInfoEXT . יכול להיות שגם בהקשרים מרחביים אחרים שמוגדרים עם XR_SPATIAL_CAPABILITY_ANCHOR_EXT אפשר יהיה לגלות את העוגן החדש שנוצר, אבל עם XrSpatialEntityIdEXT אחר, כי XrSpatialEntityIdEXT מסוים הוא ייחודי ל-XrSpatialContextEXT שלו.
שימוש תקין (משתמע)
- חובה להפעיל את התוסף
XR_EXT_spatial_anchorלפני שקוראים לפונקציה xrCreateSpatialAnchorEXT -
spatialContextחייב להיות כינוי תקין של XrSpatialContextEXT -
createInfoחייב להיות מצביע למבנה XrSpatialAnchorCreateInfoEXT תקין -
anchorEntityIdחייב להיות מצביע לערךXrSpatialEntityIdEXT -
anchorEntityחייב להיות מצביע לכינוי XrSpatialEntityEXT
קודי החזרה
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
תנוחת העוגן של השאילתה
אחרי שנוצר העוגן, זמן הריצה אמור להתאים את המיקום והכיוון שלו לאורך זמן ביחס למרחבים אחרים כדי לשמור על ההתאמה הטובה ביותר למיקום המקורי שלו בעולם האמיתי, גם אם זה משנה את הקשר של העוגן ל-XrSpatialAnchorCreateInfoEXT :: baseSpace המקורי ששימש לאתחול שלו.
האפליקציה יכולה להשתמש ב-xrCreateSpatialUpdateSnapshotEXT עם XrSpatialEntityEXT של העוגן כדי ליצור XrSpatialSnapshotEXT חדש, ואז לשלוח שאילתה לרכיב XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT מאותו קובץ snapshot באמצעות 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 :
קבועי Enum חדשים
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 בשם האפליקציה ומספק לה את נקודת האחיזה של הישות לשימוש עם xrCreateSpatialUpdateSnapshotEXT .
היסטוריית הגרסאות
גרסה 1, 10.07.2024 (Nihav Jain, Google)
- תיאור התוסף הראשוני