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 は、locationCount XrPosef 構造体の配列へのポインタでなければなりません。
  • 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);

パラメータの説明

アプリは、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_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 は、アンカー エンティティのロケーションです。

有効な使用方法(暗黙的)

アンカーポーズをクエリする

アンカーが作成された後、ランタイムは、元の現実世界の場所との最適な位置合わせを維持するために、他の空間を基準としてアンカーの位置と向きを時間の経過とともに調整すべきです。これは、アンカーの初期化に使用された元の 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_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 日(Nihav Jain、Google)

    • 拡張機能の初期説明