XR_ANDROID_spatial_entity_bound_anchor

Name String

XR_ANDROID_spatial_entity_bound_anchor

Loại tiện ích

Phần mở rộng thực thể

Số máy lẻ đã đăng ký

791

Bản sửa đổi

2

Trạng thái phê chuẩn

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

Phần phụ thuộc của tiện ích và 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ó tuyên bố nào về tài sản 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 neo vào thực thể không gian, được gọi là "neo liên kết với thực thể" trong tiện ích này.

Đ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 điểm 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ẹ, được coi là "cơ sở" của điểm 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ể để đại diện cho khung ảnh ảo và gắn neo đó 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 tế được cải thiện.

Hỗ trợ thời gian chạy

Môi trường 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 liên kết 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 định nghĩa 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 tay điều khiển cho XrInstance .
  • systemId là XrSystemId có kho lưu trữ cố định 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 kèm 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ể là NULL nếu attachableComponentCapacityInput là 0.
  • Xem chương Tham số dung lượng bộ nhớ đệm để biết nội dung mô tả chi tiết về cách truy xuất kích thước attachableComponents cần thiết.

Môi trường thời gian chạy phải luôn trả về nội dung vùng đệm giống hệt nhau từ bản liệt kê này cho systemId đã cho trong suốt thời gian hoạt động của thực thể.

Cách sử dụng hợp lệ (Ngầm ẩn)

  • Tiện ích XR_ANDROID_spatial_entity_bound_anchor phải được bật trước khi gọi xrEnumerateSpatialAnchorAttachableComponentsANDROID
  • instance phải là một tên người dù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à một con trỏ đến một mảng gồm các giá trị attachableComponentCapacityInput XrSpatialComponentTypeEXT

Mã trả về

Thành công

  • XR_SUCCESS

Không thành công

  • 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 điểm neo liên kết với thực thể không gian

Ứng dụng sử 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 định nghĩa như sau:

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

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

  • type là XrStructureType của cấu trúc này.
  • next là NULL hoặc con trỏ trỏ đến cấu trúc tiếp theo trong chuỗi cấu trúc.
  • parentId là XrSpatialEntityIdEXT của thực thể 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 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 được liệt kê bằng xrEnumerateSpatialAnchorAttachableComponentsANDROID nằm trên thực thể mẹ.

Cách sử dụng hợp lệ (Ngầm ẩn)

Mã ví dụ

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

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

Lấy tư thế neo liên kết với thực thể và mã thực thể mẹ

Mã ví dụ sau đây minh hoạ cách lấy tư thế của một điểm 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 neo liên kết với thực thể

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ợ chức năng neo liên kết với 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 tháng 8 năm 2025 (YuSheng Chang)

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