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 のライフサイクル全体を通して、ユーザーの物理環境に関するランタイムの理解が更新されると、仮想オブジェクトがアプリケーションによって配置された場所からずれて見えることがあります。これは、アプリケーションのリアリズムとユーザー エクスペリエンスの品質に影響します。仮想オブジェクトが配置される場所の近くにアンカーを作成し、そのアンカーを基準に仮想オブジェクトを常にレンダリングすることで、アプリケーションは、各仮想オブジェクトが物理環境内の同じ位置と向きに表示されるようにすることができます。また、一部の参照空間とは異なり、アンカーはシステムレベルの再センタリングの影響を受けません。

ランタイム サポート

ランタイムが空間アンカーをサポートしている場合、xrEnumerateSpatialCapabilitiesEXTXR_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 または構造体チェーン内の次の構造体へのポインタです。
  • capabilityXrSpatialCapabilityEXT です。
  • enabledComponentCount は、enabledComponents 配列内の要素の数を記述する uint32_t です。
  • enabledComponentsXrSpatialComponentTypeEXT の配列へのポインタです。

アプリは、XrSpatialContextCreateInfoEXT :: capabilityConfigsXrSpatialCapabilityConfigurationAnchorEXT 構造体へのポインタを含めることで、XR_SPATIAL_CAPABILITY_ANCHOR_EXT 空間機能を有効にできます

capabilityXR_SPATIAL_CAPABILITY_ANCHOR_EXT でない場合、ランタイムは XR_ERROR_VALIDATION_FAILURE を返さなければなりません。

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

保証対象コンポーネント

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 です。
  • locationsXrPosef の配列です。

ランタイムは、XrSpatialComponentAnchorListEXTXrSpatialComponentDataQueryResultEXT :: next チェーンに含まれているが、XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXTXrSpatialComponentDataQueryConditionEXT :: componentTypes に含まれていない場合、xrQuerySpatialComponentDataEXT から XR_ERROR_VALIDATION_FAILURE を返さなければなりません

locationCountXrSpatialComponentDataQueryResultEXT :: entityIdCountOutput より小さい場合、ランタイムは xrQuerySpatialComponentDataEXT から XR_ERROR_SIZE_INSUFFICIENT を返さなければなりません。

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

  • XrSpatialComponentAnchorListEXT を使用する前に、XR_EXT_spatial_anchor 拡張機能を有効にする必要があります
  • typeXR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT でなければなりません。
  • next は、NULL または構造体チェーン内の次の構造体への有効なポインタでなければなりません。
  • locations は、locationCount XrPosef 構造体の配列へのポインタでなければなりません。
  • locationCount パラメータは 0 より大きい値にする必要があります
構成

XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXTXrSpatialCapabilityComponentTypesEXT :: 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 配列内のこのアンカーを一意に識別できます

ランタイムは、spatialContextXR_SPATIAL_CAPABILITY_ANCHOR_EXT が構成されていない場合、xrCreateSpatialAnchorEXT から XR_ERROR_VALIDATION_FAILURE を返さなければなりません。XR_SPATIAL_CAPABILITY_ANCHOR_EXT 機能の XrSpatialContextEXT を構成する方法については、構成をご覧ください。

anchorEntity で表されるアンカーは、spatialContext の有効期間中、またはアプリが xrDestroySpatialEntityEXT を呼び出すまでの間のみ有効です。他の拡張機能では、この新しく作成されたアンカーを複数の XrSession にわたって永続化したり、プロセス境界を越えて他のアプリケーションと共有したりする機能が提供される可能性があります

新たに作成されたアンカーは、破棄されるまで、親空間コンテキストで検出可能でなければなりません。つまり、アンカーが XrSpatialDiscoverySnapshotCreateInfoEXT で設定された検出条件と一致する場合、ランタイムは spatialContextxrCreateSpatialDiscoverySnapshotAsyncEXT を使用して作成されたスナップショットに anchorEntityId を含めなければなりません。新しく作成されたアンカーは、XR_SPATIAL_CAPABILITY_ANCHOR_EXT で構成された他の空間コンテキストでも検出できる場合があります。ただし、特定の XrSpatialEntityIdEXT はその XrSpatialContextEXT に固有であるため、XrSpatialEntityIdEXT は異なります。

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

  • xrCreateSpatialAnchorEXT を呼び出す前に XR_EXT_spatial_anchor 拡張機能を有効にする必要があります
  • spatialContext 有効な XrSpatialContextEXT ハンドルでなければなりません
  • createInfo は、有効な XrSpatialAnchorCreateInfoEXT 構造体へのポインタでなければなりません
  • anchorEntityIdXrSpatialEntityIdEXT 値へのポインタでなければなりません。
  • anchorEntityXrSpatialEntityEXT ハンドルへのポインタでなければなりません。

戻りコード

成功

  • 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_ANDROIDXR_ANDROID_spatial_entity_bound_anchor が有効の場合)
  • XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXTXR_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 との関係が変化する可能性があります。

アプリケーションは、アンカーの XrSpatialEntityEXTxrCreateSpatialUpdateSnapshotEXT を使用して新しい XrSpatialSnapshotEXT を作成し、xrQuerySpatialComponentDataEXT を使用してそのスナップショットから XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT コンポーネントをクエリできます。アプリケーションは、XrSpatialComponentDataQueryResultEXT :: nextXrSpatialComponentAnchorListEXT を追加して、アンカーの最新の位置情報を取得できます

ランタイムは、新しく作成されたアンカーのトラッキング状態を 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-07-10(Nihav Jain、Google)

    • 拡張機能の最初の説明