XR_EXT_spatial_anchor
Name String
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 のライフタイム全体を通じて、ランタイムがユーザーの物理環境を理解するにつれて、仮想オブジェクトがアプリケーションによって配置された場所から離れていくように見える可能性があります。これは、アプリケーションのリアリズムとユーザー エクスペリエンスの品質に影響します。仮想オブジェクトが配置されている場所の近くにアンカーを作成し、常にそのアンカーを基準として仮想オブジェクトをレンダリングすることで、アプリケーションは、各仮想オブジェクトが物理環境で同じ位置と向きを維持しているように見せることができます。また、特定の参照空間とは異なり、アンカーはシステムレベルの再センタリングの影響を受けません。
ランタイム サポート
ランタイムが空間アンカーをサポートしている場合、xrEnumerateSpatialCapabilitiesEXT で XR_SPATIAL_CAPABILITY_ANCHOR_EXT を列挙することで、これを示さなければなりません。
構成
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は、enabledComponents配列内の要素の数を表すuint32_tです。enabledComponentsは XrSpatialComponentTypeEXT の配列へのポインタです。
アプリは、XrSpatialContextCreateInfoEXT :: capabilityConfigs に XrSpatialCapabilityConfigurationAnchorEXT 構造体へのポインタを含めることで、XR_SPATIAL_CAPABILITY_ANCHOR_EXT 空間機能を有効にできます。
capability が XR_SPATIAL_CAPABILITY_ANCHOR_EXT でない場合、ランタイムは XR_ERROR_VALIDATION_FAILURE を返さなければなりません。
有効な使用方法(暗黙的)
- XrSpatialCapabilityConfigurationAnchorEXT を使用する前に、
XR_EXT_spatial_anchor拡張機能を有効にする必要があります。 -
typeはXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXTにする必要があります。 -
nextは、NULLまたは構造体チェーン内の次の構造体への有効なポインタでなければなりません。 -
capabilityは、有効な XrSpatialCapabilityEXT 値でなければなりません -
enabledComponentsは、enabledComponentCount個の有効な XrSpatialComponentTypeEXT 値の配列へのポインタでなければなりません。 -
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は、locations配列内の要素の数を表すuint32_tです。locationsは XrPosef の配列です。
XrSpatialComponentAnchorListEXT が XrSpatialComponentDataQueryResultEXT :: next チェーンに含まれているが、XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT が XrSpatialComponentDataQueryConditionEXT :: componentTypes に含まれていない場合、ランタイムは xrQuerySpatialComponentDataEXT から XR_ERROR_VALIDATION_FAILURE を返さなければなりません。
locationCount が XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput より小さい場合、ランタイムは xrQuerySpatialComponentDataEXT から XR_ERROR_SIZE_INSUFFICIENT を返さなければなりません。
有効な使用方法(暗黙的)
- XrSpatialComponentAnchorListEXT を使用する前に、
XR_EXT_spatial_anchor拡張機能を有効にする必要があります。 -
typeはXR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXTにする必要があります。 -
nextは、NULLまたは構造体チェーン内の次の構造体への有効なポインタでなければなりません。 -
locationsは、locationCountXrPosef 構造体の配列へのポインタでなければなりません。 -
locationCountパラメータは0より大きい値にする必要があります。
構成
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT が XrSpatialCapabilityComponentTypesEXT :: componentTypes で列挙されている場合、アプリは、このコンポーネントをサポートする機能の 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 を返さなければなりません。XR_SPATIAL_CAPABILITY_ANCHOR_EXT 機能用に XrSpatialContextEXT を構成する方法については、構成をご覧ください。
anchorEntity で表されるアンカーは、spatialContext の存続期間中、またはアプリケーションが xrDestroySpatialEntityEXT を呼び出すまで(いずれか早い方)のみ有効です。他の拡張機能では、この新しく作成されたアンカーを複数の XrSession にわたって保持したり、プロセス境界を越えて他のアプリケーションと共有したりする機能が提供される場合があります。
新しく作成されたアンカーは、破棄されるまで、親の空間コンテキストで検出可能でなければなりません。つまり、アンカーが XrSpatialDiscoverySnapshotCreateInfoEXT で設定された検出条件に一致する場合、ランタイムは xrCreateSpatialDiscoverySnapshotAsyncEXT を使用して作成された spatialContext のスナップショットに anchorEntityId を含める必要があります。新しく作成されたアンカーは、XR_SPATIAL_CAPABILITY_ANCHOR_EXT で構成された他の空間コンテキストでも検出可能ですが、特定の XrSpatialEntityIdEXT は XrSpatialContextEXT に固有であるため、XrSpatialEntityIdEXT は異なります。
有効な使用方法(暗黙的)
-
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_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 ハンドルでなければなりません
アンカーポーズをクエリする
アンカーが作成された後、ランタイムは、元の現実世界の場所との最適な位置合わせを維持するために、他の空間を基準としてアンカーの位置と向きを時間の経過とともに調整すべきです。これは、アンカーの初期化に使用された元の XrSpatialAnchorCreateInfoEXT :: baseSpace とアンカーの関係が変化する場合でも同様です。
アプリケーションは、アンカーの XrSpatialEntityEXT で xrCreateSpatialUpdateSnapshotEXT を使用して新しい XrSpatialSnapshotEXT を作成し、xrQuerySpatialComponentDataEXT を使用してそのスナップショットから XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT コンポーネントをクエリできます。アプリは、XrSpatialComponentAnchorListEXT を XrSpatialComponentDataQueryResultEXT :: next に追加して、アンカーの最新の位置情報を取得できます。
ランタイムは、新しく作成されたアンカーのトラッキング状態を XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT に設定する場合があります。トラッキング状態が XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT の場合、アプリケーションは XrSpatialComponentDataQueryResultEXT :: entityStates で提供されるアンカー エンティティの状態と、エンティティのアンカー コンポーネント データのみを読み取る必要があります。
アンカーの使用に関するガイドライン
- 各アンカーのポーズは、他のアンカーや空間とは独立して調整されます。別々にアンカーされた仮想オブジェクトは、互いに相対的に移動または回転する可能性があり、これらの仮想オブジェクトが互いに相対的に同じ位置に留まることが期待される場合に、空間階層が崩れることがあります。このような場合、アプリは、互いに相対的に移動しないすべての仮想オブジェクトに同じアンカーを再利用すべきです。
- アプリは、使用されなくなったアンカーの 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));
新しいコマンド
新しい構造
新しい列挙型定数
XR_EXT_SPATIAL_ANCHOR_EXTENSION_NAMEXR_EXT_spatial_anchor_SPEC_VERSION-
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 がエンティティ ハンドルだけでなくエンティティ ID も出力するのはなぜですか?
- 解決済み
- 回答: xrCreateSpatialAnchorEXT 関数は、出力としてエンティティ ID のみを提供し、アプリケーションは xrCreateSpatialEntityFromIdEXT を使用してその ID のエンティティ ハンドルを作成できます。ただし、アプリケーションがフレームごとにアンカーポーズをクエリするアンカーの一般的な使用方法を考えると、エンティティ ハンドルを入力として必要とする「更新スナップショット」で使用するのに適しています。この一般的なユースケースを想定して、xrCreateSpatialAnchorEXT はアプリケーションに代わって xrCreateSpatialEntityFromIdEXT を実行し、xrCreateSpatialUpdateSnapshotEXT で使用するエンティティ ハンドルを提供します。
変更履歴
リビジョン 1、2024 年 7 月 10 日(Nihav Jain、Google)
- 拡張機能の初期説明