XR_EXT_spatial_anchor
Name String
XR_EXT_spatial_anchor
拡張機能のタイプ
インスタンス拡張機能
Registered Extension Number
763
リビジョン
1
Ratification Status(批准ステータス)
批准
拡張機能とバージョンの依存関係
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
Anchor コンポーネント
コンポーネント データ
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 で設定された検出条件と一致する場合、ランタイムは spatialContext の xrCreateSpatialDiscoverySnapshotAsyncEXT を使用して作成されたスナップショットに anchorEntityId を含めなければなりません。新しく作成されたアンカーは、XR_SPATIAL_CAPABILITY_ANCHOR_EXT で構成された他の空間コンテキストでも検出できる場合があります。ただし、特定の XrSpatialEntityIdEXT はその XrSpatialContextEXT に固有であるため、XrSpatialEntityIdEXT は異なります。
有効な使用方法(暗黙的)
- xrCreateSpatialAnchorEXT を呼び出す前に
XR_EXT_spatial_anchor拡張機能を有効にする必要があります -
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 コンポーネントをクエリできます。アプリケーションは、XrSpatialComponentDataQueryResultEXT :: next に XrSpatialComponentAnchorListEXT を追加して、アンカーの最新の位置情報を取得できます。
ランタイムは、新しく作成されたアンカーのトラッキング状態を 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_VERSIONXrSpatialCapabilityEXT を拡張する :
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-07-10(Nihav Jain、Google)
- 拡張機能の最初の説明