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는locationCountXrPosef 구조의 배열에 대한 포인터여야 합니다. -
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);
파라미터 설명
spatialContext는 이전에 xrCreateSpatialContextAsyncEXT를 사용하여 만든 XrSpatialContextEXT입니다.createInfo는 XrSpatialAnchorCreateInfoEXT에 대한 포인터입니다.anchorEntityId는 앵커 항목의 ID가 반환되는XrSpatialEntityIdEXT에 대한 포인터입니다.anchorEntity은 앵커 항목의 핸들이 반환되는 XrSpatialEntityEXT에 대한 포인터입니다.
애플리케이션은 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_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_FAILUREXR_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은 앵커 항목의 위치입니다.
올바른 사용 (암시적)
- XrSpatialAnchorCreateInfoEXT를 사용하기 전에
XR_EXT_spatial_anchor확장 프로그램을 사용 설정해야 합니다. -
type은(는)XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT여야 합니다. -
next는NULL또는 구조 체인의 다음 구조에 대한 유효한 포인터여야 합니다. 참고: XrSpatialAnchorParentANDROID -
baseSpace는 유효한 XrSpace 핸들이어야 합니다(must).
앵커 포즈 쿼리
앵커가 생성된 후 런타임은 원래 실제 위치에 최대한 정렬되도록 시간이 지남에 따라 다른 공간을 기준으로 위치와 방향을 조정해야 합니다(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_NAMEXR_EXT_spatial_anchor_SPEC_VERSION-
XR_SPATIAL_CAPABILITY_ANCHOR_EXT
-
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가 항목 핸들뿐만 아니라 항목 ID도 출력하는 이유는 무엇인가요?
- 해결됨
- 답변: xrCreateSpatialAnchorEXT 함수는 항목 ID만 출력으로 제공했을 수 있으며 애플리케이션은 xrCreateSpatialEntityFromIdEXT를 사용하여 해당 ID의 항목 핸들을 만들 수 있습니다. 하지만 애플리케이션이 프레임마다 앵커 포즈를 쿼리하는 앵커의 일반적인 사용을 고려할 때, 엔티티 핸들을 입력으로 요구하는 '업데이트 스냅샷'에서 사용하기에 적합한 후보가 됩니다. 이 일반적인 사용 사례를 예상하여 xrCreateSpatialAnchorEXT는 애플리케이션을 대신하여 xrCreateSpatialEntityFromIdEXT를 실행하고 xrCreateSpatialUpdateSnapshotEXT와 함께 사용할 항목 핸들을 제공합니다.
버전 기록
버전 1, 2024년 7월 10일 (니하브 자인, Google)
- 초기 확장 프로그램 설명