XR_EXT_spatial_anchor

이름 문자열

XR_EXT_spatial_anchor

확장 프로그램 유형

인스턴스 확장 프로그램

등록된 내선 번호

763

버전

1

승인 상태

비준됨

확장 프로그램 및 버전 종속 항목

XR_EXT_spatial_entity

도움을 주신 분들

니하브 자인, Google
나탈리 플뢰리, Meta
유이치 타구치, Meta
론 베셈스, Meta
인 리, Microsoft
지미 알람파람빌, ByteDance
지펑 리우, ByteDance
준 얀, ByteDance

개요

이 확장 프로그램은 XR_EXT_spatial_entity를 기반으로 하며, 애플리케이션이 공간 앵커를 만들 수 있도록 합니다. 공간 앵커는 사용자의 실제 환경에 있는 임의의 지점으로, 런타임에서 추적됩니다. 그러면 런타임은 다른 모든 공간 및 앵커와 관계없이 필요에 따라 시간 경과에 따라 앵커 원점의 위치와 방향을 조정하여(SHOULD) 실제 세계에 대한 원래 매핑을 유지해야 합니다.

XrSpatialContextEXT 내에서 지정된 위치와 방향을 추적하는 앵커는 XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT 구성요소가 있는 공간 항목으로 표현됩니다.

앵커 사용의 이점

XrSpatialContextEXT의 전체 기간 동안 사용자의 물리적 환경에 관한 런타임의 이해가 업데이트됨에 따라 가상 객체가 애플리케이션에서 배치한 위치에서 멀어지는 것처럼 보일 수 있으며, 이는 애플리케이션의 사실성과 사용자 환경의 품질에 영향을 미칩니다. 가상 객체가 배치된 위치 근처에 앵커를 만든 다음 항상 앵커를 기준으로 가상 객체를 렌더링하면 애플리케이션은 각 가상 객체가 물리적 환경에서 동일한 위치와 방향에 유지되는 것처럼 보이도록 할 수 있습니다. 또한 특정 참조 공간과 달리 앵커는 시스템 수준의 최근 센터링의 영향을 받지 않습니다.

런타임 지원

런타임이 공간 앵커를 지원하는 경우 xrEnumerateSpatialCapabilitiesEXT에서 XR_SPATIAL_CAPABILITY_ANCHOR_EXT를 열거하여 이를 나타내야 합니다(must).

구성

XrSpatialCapabilityConfigurationAnchorEXT 구조는 다음과 같이 정의됩니다.

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

회원 설명

  • type는 이 구조의 XrStructureType입니다.
  • next는 NULL 또는 구조 체인의 다음 구조에 대한 포인터입니다.
  • thought capability는 XrSpatialCapabilityEXT입니다.
  • enabledComponentCount은 enabledComponents 배열의 요소 수를 설명하는 uint32_t입니다.
  • enabledComponents는 XrSpatialComponentTypeEXT 배열의 포인터입니다.

애플리케이션은 XrSpatialContextCreateInfoEXT :: capabilityConfigs의 XrSpatialCapabilityConfigurationAnchorEXT 구조에 대한 포인터를 포함하여 XR_SPATIAL_CAPABILITY_ANCHOR_EXT 공간 기능을 사용 설정할 수 있습니다.

capability가 XR_SPATIAL_CAPABILITY_ANCHOR_EXT가 아닌 경우 런타임은 XR_ERROR_VALIDATION_FAILURE를 반환해야 합니다(must).

올바른 사용 (암시적)

  • 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를 지원하는 런타임은 이 기능으로 생성되거나 검색된 모든 항목의 보장된 구성요소로 다음 공간 구성요소를 제공해야 하며(must) xrEnumerateSpatialCapabilityComponentTypesEXT에 열거해야 합니다(must).

  • 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은 locations 배열의 요소 수를 설명하는 uint32_t입니다.
  • locations는 XrPosef의 배열입니다.

XrSpatialComponentAnchorListEXT가 XrSpatialComponentDataQueryResultEXT :: next 체인에 있지만 XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT가 XrSpatialComponentDataQueryConditionEXT :: componentTypes에 포함되지 않은 경우 런타임은 xrQuerySpatialComponentDataEXT에서 XR_ERROR_VALIDATION_FAILURE를 반환해야 합니다(MUST).

locationCount가 XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput보다 작은 경우 런타임은 xrQuerySpatialComponentDataEXT에서 XR_ERROR_SIZE_INSUFFICIENT를 반환해야 합니다(must).

올바른 사용 (암시적)

  • XrSpatialComponentAnchorListEXT를 사용하기 전에 XR_EXT_spatial_anchor 확장 프로그램을 사용 설정해야 합니다.
  • type은(는) XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT여야 합니다.
  • next는 NULL 또는 구조 체인의 다음 구조에 대한 유효한 포인터여야 합니다.
  • locations는 locationCount XrPosef 구조의 배열에 대한 포인터여야 합니다.
  • locationCount 매개변수는 0보다 커야 합니다.
구성

일부 기능의 XrSpatialCapabilityComponentTypesEXT :: componentTypes에 XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT가 열거된 경우 애플리케이션은 이 구성요소를 지원하는 기능의 XrSpatialCapabilityConfigurationBaseHeaderEXT 파생 구조의 XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents 목록에 열거자를 포함하여 이를 사용 설정할 수 있습니다.

이 구성요소는 XrSpatialCapabilityConfigurationBaseHeaderEXT :: next 체인에 포함하기 위해 특별한 구성이 필요하지 않습니다.

공간 앵커 만들기

xrCreateSpatialAnchorEXT 함수는 다음과 같이 정의됩니다.

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

파라미터 설명

애플리케이션은 xrCreateSpatialAnchorEXT를 사용하여 공간 앵커를 만들 수 있습니다.

앵커의 업데이트된 구성요소 데이터를 가져오려면 스냅샷을 만들 때 anchorEntity에 채워진 값을 XrSpatialUpdateSnapshotCreateInfoEXT :: entities에 전달합니다. 애플리케이션은 xrQuerySpatialComponentDataEXT를 사용할 때 anchorEntityId를 사용하여 XrSpatialComponentDataQueryResultEXT :: entityIds 배열에서 이 앵커를 고유하게 식별할 수 있습니다.

spatialContext에 XR_SPATIAL_CAPABILITY_ANCHOR_EXT가 구성되지 않은 경우 런타임은 xrCreateSpatialAnchorEXT에서 XR_ERROR_VALIDATION_FAILURE를 반환해야 합니다(must). XR_SPATIAL_CAPABILITY_ANCHOR_EXT 기능에 대해 XrSpatialContextEXT를 구성하는 방법은 구성을 참고하세요.

anchorEntity로 표현되는 앵커는 spatialContext의 전체 기간 동안 또는 애플리케이션이 xrDestroySpatialEntityEXT를 호출할 때까지(둘 중 먼저 발생하는 시점)만 유효합니다. 다른 확장 프로그램은 새로 생성된 이 앵커를 여러 XrSession에서 저장하거나 프로세스 경계를 넘어 다른 애플리케이션과 공유하는 기능을 제공할 수 있습니다.

새로 만든 앵커는 소멸될 때까지 상위 공간 컨텍스트에서 검색 가능해야 합니다(MUST). 즉, 앵커가 XrSpatialDiscoverySnapshotCreateInfoEXT에 설정된 탐색 기준과 일치하는 경우 런타임은 spatialContext의 xrCreateSpatialDiscoverySnapshotAsyncEXT를 사용하여 만든 스냅샷에 anchorEntityId를 포함해야 합니다(must). 새로 생성된 앵커는 XR_SPATIAL_CAPABILITY_ANCHOR_EXT로 구성된 다른 공간 컨텍스트에서도 검색할 수 있지만, 특정 XrSpatialEntityIdEXT는 XrSpatialContextEXT에 고유하므로 XrSpatialEntityIdEXT는 다릅니다.

올바른 사용 (암시적)

  • xrCreateSpatialAnchorEXT를 호출하기 전에 XR_EXT_spatial_anchor 확장 프로그램을 사용 설정해야 합니다.
  • spatialContext는 유효한 XrSpatialContextEXT 핸들이어야 합니다.
  • createInfo는 유효한 XrSpatialAnchorCreateInfoEXT 구조에 대한 포인터여야 합니다(must).
  • anchorEntityId는 XrSpatialEntityIdEXT 값에 대한 포인터여야 합니다.
  • anchorEntity는 XrSpatialEntityEXT 핸들의 포인터여야 합니다(must).

반품 코드

성공

  • 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는 pose가 적용되는 XrSpace입니다.
  • time는 baseSpace가 위치한 (그리고 pose가 적용되는) XrTime입니다.
  • pose은 앵커 항목의 위치입니다.

올바른 사용 (암시적)

앵커 포즈 쿼리

앵커가 생성된 후 런타임은 원래 실제 위치에 최대한 정렬되도록 시간이 지남에 따라 다른 공간을 기준으로 위치와 방향을 조정해야 합니다(should). 이로 인해 앵커와 초기화에 사용된 원래 XrSpatialAnchorCreateInfoEXT :: baseSpace의 관계가 변경되더라도 마찬가지입니다.

애플리케이션은 앵커의 XrSpatialEntityEXT와 함께 xrCreateSpatialUpdateSnapshotEXT를 사용하여 새 XrSpatialSnapshotEXT를 만든 다음 xrQuerySpatialComponentDataEXT를 사용하여 해당 스냅샷에서 XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT 구성요소를 쿼리할 수 있습니다. 애플리케이션은 XrSpatialComponentAnchorListEXT를 XrSpatialComponentDataQueryResultEXT :: next에 추가하여 앵커의 최신 위치 데이터를 가져올 수 있습니다(can).

런타임은 새로 생성된 앵커의 추적 상태를 XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT로 설정할 수 있습니다. 애플리케이션은 추적 상태가 XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT인 경우에만 XrSpatialComponentDataQueryResultEXT :: entityStates에 제공된 앵커 항목의 상태와 항목의 앵커 구성요소 데이터를 읽어야 합니다(must).

앵커 사용 가이드라인

  • 각 앵커의 포즈는 다른 앵커나 공간과 독립적으로 조정됩니다. 별도로 고정된 가상 객체는 서로 상대적으로 이동하거나 회전하여 이러한 가상 객체가 서로 상대적으로 제자리에 있어야 하는 경우 공간 계층 구조를 깨뜨릴 수 있습니다. 이러한 경우 애플리케이션은 서로 상대적으로 움직이지 않는 모든 가상 객체에 동일한 앵커를 재사용해야 합니다(should).
  • 애플리케이션은 더 이상 사용되지 않는 앵커의 XrSpatialEntityEXT 핸들을 폐기하여 런타임이 해당 앵커를 추적하는 데 사용할 수 있는 리소스를 확보해야 합니다(should).

예제 코드

앵커 기능 구성

다음 예시에서는 공간 컨텍스트를 만들 때 앵커 기능을 구성하는 방법을 보여줍니다.

// 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));

새 명령어

새로운 구조

새 enum 상수

  • 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가 항목 핸들뿐만 아니라 항목 ID도 출력하는 이유는 무엇인가요?

    • 해결됨
    • 답변: xrCreateSpatialAnchorEXT 함수는 항목 ID만 출력으로 제공했을 수 있으며 애플리케이션은 xrCreateSpatialEntityFromIdEXT를 사용하여 해당 ID의 항목 핸들을 만들 수 있습니다. 하지만 애플리케이션이 프레임마다 앵커 포즈를 쿼리하는 앵커의 일반적인 사용을 고려할 때, 엔티티 핸들을 입력으로 요구하는 '업데이트 스냅샷'에서 사용하기에 적합한 후보가 됩니다. 이 일반적인 사용 사례를 예상하여 xrCreateSpatialAnchorEXT는 애플리케이션을 대신하여 xrCreateSpatialEntityFromIdEXT를 실행하고 xrCreateSpatialUpdateSnapshotEXT와 함께 사용할 항목 핸들을 제공합니다.

버전 기록

  • 버전 1, 2024년 7월 10일 (니하브 자인, Google)

    • 초기 확장 프로그램 설명