XR_ANDROID_spatial_entity_bound_anchor

Name String

XR_ANDROID_spatial_entity_bound_anchor

Loại phần mở rộng

Tiện ích Instance

Số máy nhánh đã đăng ký

791

Bản sửa đổi

2

Trạng thái phê chuẩn

Chưa được phê chuẩn

Phần mở rộng và các phần phụ thuộc của phiên bản

XR_EXT_spatial_anchor

Ngày sửa đổi gần đây nhất

2025-08-18

Trạng thái IP

Không có thông báo xác nhận quyền sở hữu nào đã biết về quyền sở hữu trí tuệ.

Cộng tác viên

YuSheng Chang, Google
Kyle Chen, Google
Nihav Jain, Google
Levana Chen, Google
Spencer Quin, Google

Tổng quan

Tiện ích này cho phép các ứng dụng tạo và đính kèm các điểm neo vào các thực thể không gian. Trong tiện ích này, các điểm neo này được gọi là "điểm neo liên kết với thực thể".

Điểm neo liên kết với thực thể được biểu thị dưới dạng một thực thể không gian có (hoặc "có") thành phần XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT và thành phần XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT. Thành phần XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT lưu trữ XrSpatialEntityIdEXT của thực thể mẹ mà điểm neo được đính kèm.

Tư thế của một neo liên kết với thực thể luôn được biểu thị bằng một độ lệch cố định so với thực thể mẹ. Thực thể mẹ được coi là "cơ sở" của neo. Ví dụ: giả sử người dùng có một khung ảnh ảo gắn vào tường, người dùng sử dụng một neo liên kết với thực thể để biểu thị khung ảnh ảo và gắn khung ảnh đó vào thực thể tường. Nhờ đó, vị trí tương đối giữa bức tường và khung ảnh luôn nhất quán khi thông tin ước tính theo dõi của bức tường thực được cải thiện.

Hỗ trợ thời gian chạy

Thời gian chạy phải hỗ trợ ít nhất một tiện ích theo dõi không gian, ví dụ: XR_EXT_spatial_plane_tracking. Nếu thời gian chạy hỗ trợ neo được liên kết với thực thể không gian, thì thời gian chạy đó phải cung cấp ít nhất một thành phần có thể đính kèm bằng cách liệt kê hàm xrEnumerateSpatialAnchorAttachableComponentsANDROID. Ứng dụng có thể liệt kê các thành phần có thể đính kèm bằng cách sử dụng xrEnumerateSpatialAnchorAttachableComponentsANDROID .

Hàm xrEnumerateSpatialAnchorAttachableComponentsANDROID được xác định như sau:

XrResult xrEnumerateSpatialAnchorAttachableComponentsANDROID(
    XrInstance                                  instance,
    XrSystemId                                  systemId,
    uint32_t                                    attachableComponentCapacityInput,
    uint32_t*                                   attachableComponentCountOutput,
    XrSpatialComponentTypeEXT*                  attachableComponents);

Nội dung mô tả về tham số

  • instance là một handle cho XrInstance .
  • systemIdXrSystemId mà các kho lưu trữ duy trì không gian sẽ được liệt kê.
  • attachableComponentCapacityInput là dung lượng của mảng attachableComponents hoặc 0 để cho biết yêu cầu truy xuất dung lượng cần thiết.
  • attachableComponentCountOutput là số lượng thành phần có thể gắn hoặc dung lượng cần thiết trong trường hợp attachableComponentCapacityInput không đủ.
  • attachableComponents là một mảng XrSpatialComponentTypeEXT . Giá trị này có thểNULL nếu attachableComponentCapacityInput là 0.
  • Hãy xem chương Tham số kích thước vùng đệm để biết nội dung mô tả chi tiết về cách truy xuất kích thước attachableComponents bắt buộc.

Thời gian chạy phải luôn trả về nội dung bộ đệm giống hệt nhau từ quá trình liệt kê này cho systemId đã cho trong suốt thời gian tồn tại của phiên bản.

Sử dụng hợp lệ (Ngầm ẩn)

  • Bạn phải bật tiện ích XR_ANDROID_spatial_entity_bound_anchor trước khi gọi xrEnumerateSpatialAnchorAttachableComponentsANDROID
  • instance phải là một đối tượng XrInstance hợp lệ
  • attachableComponentCountOutput phải là con trỏ đến giá trị uint32_t
  • Nếu attachableComponentCapacityInput không phải là 0 , thì attachableComponents phải là con trỏ đến một mảng gồm các giá trị attachableComponentCapacityInput XrSpatialComponentTypeEXT

Mã trả về

Thành công

  • XR_SUCCESS

Thất bại

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_SIZE_INSUFFICIENT
  • XR_ERROR_SYSTEM_INVALID
  • XR_ERROR_VALIDATION_FAILURE

Tạo một điểm neo được liên kết với thực thể không gian

Các ứng dụng dùng hàm xrCreateSpatialAnchorEXT để tạo một neo. Nếu muốn tạo một neo liên kết với thực thể được đính kèm vào một thực thể không gian, ứng dụng có thể liên kết cấu trúc XrSpatialAnchorParentANDROID với con trỏ tiếp theo của cấu trúc XrSpatialAnchorCreateInfoEXT khi gọi hàm xrCreateSpatialAnchorEXT.

Cấu trúc XrSpatialAnchorParentANDROID được xác định như sau:

typedef struct XrSpatialAnchorParentANDROID {
    XrStructureType         type;
    const void*             next;
    XrSpatialEntityIdEXT    parentId;
} XrSpatialAnchorParentANDROID;

Nội dung mô tả thành viên

  • typeXrStructureType của cấu trúc này.
  • nextNULL hoặc con trỏ đến cấu trúc tiếp theo trong chuỗi cấu trúc.
  • parentIdXrSpatialEntityIdEXT của thực thể mà điểm neo sẽ được đính kèm.

Thời gian chạy phải đảm bảo rằng khoảng cách giữa thực thể mẹ và điểm neo luôn nhất quán, trong đó khoảng cách là tư thế của điểm neo đến bề mặt gần nhất của thực thể mẹ dọc theo pháp tuyến của bề mặt. Tư thế của tâm neo được cập nhật dựa trên vị trí của thực thể mẹ và khoảng cách đến bề mặt của thực thể mẹ, bất kể thực thể mẹ có bao nhiêu thành phần có thể đính kèm.

Thời gian chạy phải trả về XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT từ xrCreateSpatialAnchorEXT nếu XrSpatialAnchorParentANDROID ::parentId không phải là mã nhận dạng hợp lệ cho xrCreateSpatialAnchorEXT :: spatialContext .

Thời gian chạy phải trả về XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID từ xrCreateSpatialAnchorEXT nếu không có thành phần nào do xrEnumerateSpatialAnchorAttachableComponentsANDROID liệt kê trên thực thể mẹ.

Sử dụng hợp lệ (Ngầm ẩn)

Mã ví dụ

Tạo neo được liên kết với thực thể không gian

Đoạn mã ví dụ sau đây minh hoạ cách tạo một neo liên kết với thực thể và đính kèm neo đó vào một thực thể theo dõi mặt phẳng không gian.

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

Nhận tư thế của điểm neo liên kết với thực thể và mã nhận dạng thực thể mẹ

Đoạn mã ví dụ sau đây minh hoạ cách lấy tư thế của một neo liên kết với thực thể và mã nhận dạng của thực thể mẹ.

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

Liệt kê các Thành phần có thể đính kèm và kiểm tra khả năng liên kết neo của thực thể

Đoạn mã ví dụ sau đây minh hoạ cách liệt kê các thành phần có thể đính kèm và kiểm tra xem thời gian chạy có hỗ trợ khả năng neo liên kết thực thể hay không.

// 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.
// ...

Lệnh mới

Cấu trúc mới

Hằng số Enum mới

  • XR_ANDROID_SPATIAL_ENTITY_BOUND_ANCHOR_EXTENSION_NAME
  • XR_ANDROID_spatial_entity_bound_anchor_SPEC_VERSION
  • Mở rộng XrResult :

    • XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID
  • Mở rộng XrStructureType :

    • XR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROID

Vấn đề

Danh sách phiên bản

  • Bản sửa đổi 1, ngày 18/8/2025 (YuSheng Chang)

    • Nội dung mô tả ban đầu của tiện ích.
  • Bản sửa đổi 2, ngày 16/12/2025 (Kyle Chen)