深度データの生成

深度マップを利用して没入感のあるAR体験を生み出す。

概要

現在の技術を駆使すれば、平均的なモバイル端末でも、シーン内のカメラの位置を追跡して、平面を検出することができます。たとえば、現実世界の空いている面に仮想のキャラクターを配置し、それを撮影することができます。

ただし、AR体験をさらに面白くするには、仮想キャラクターを現実世界に立たせるだけではなく、現実世界とインタラクトできるようにします。シーンの深度を理解することで、オクルージョンやナビゲーション、衝突、被写界深度エフェクトなど、数多くの機能を活用できるようになります。

ARDKの深度出力を生成するには、カラー画像の入力をディープラーニングアルゴリズムに送ります。

  • 深度ベースの機能は、深度センサーが搭載されたデバイスだけでなく、より広範囲なデバイスでも使用できますが、センサーが搭載されている場合には使用されます。

  • 深度アルゴリズムは、屋内外の環境、建物の規模、より高い距離範囲(0.2m~100m)で動作します。

  • 深度アルゴリズムでは、結果を出力するために必要なカメラの初期動作を最小限に抑え、動く物体にもすぐに対応します。

  • 深度は、サブセット(例: 人々)だけでなく、すべてのオブジェクトに対して出力されます。

このページでは、深度推定を有効にする方法や、深度のrawデータにアクセスする方法、推定精度を最適化するために留意すべき点を説明します。ARDKには、Unityのシーンにドロップすることで、深度ベースのエフェクト( オクルージョン )を素早く追加できるクラスがいくつか付属しています。

深度推定を有効にする

深度推定を有効にするには、次の操作を行います。

デバイスが深度推定に対応しているかどうかを確認します。対応デバイスの詳細なリストは、ARDKの システム要件 のページを参照してください。

using Niantic.ARDK.AR.Configuration;

var isSupported = ARWorldTrackingConfigurationFactory.CheckDepthEstimationSupport();

ここで返される値は、あくまで推奨値です。深度推定は、サポート対象外のデバイスでも動作しますが、パフォーマンスや精度、安定性のレベルは低下します。

ARSession を設定して実行し、データの生成を開始します。

void RunWithDepth(IARSession arSession)
{
  var config = ARWorldTrackingConfigurationFactory.Create();

  // Enabling IsDepthEnabled is required to generate raw depth estimation data.
  config.IsDepthEnabled = true;

  // Default/recommended value is 20 to balance resource consumption with performance.
  config.DepthTargetFrameRate = 20;

  arSession.Run(config);
}

セッションで推定値を更新するフレームレートを設定するには、 DepthTargetFrameRate を使用します。この値を大きくすると、更新頻度を上げることができますが、同時にパフォーマンスが大幅に低下する原因になります(深度推定は処理に時間がかかるため)。最初は目標値を20fpsに設定することをお勧めします。アプリケーションの要件に合わせて、値を微調整してください。

深度データにアクセスする

深度データは、 IARFrame.Depth プロパティを使用してアクセスできます。最新のフレームを取得するには、 IARSession.CurrentFrame プロパティを使用するか、 IARSession.FrameUpdated イベントをサブスクライブします。

深度データを使用する際は、次の点に注意してください。

  • ARFrameの Depth 値は、アルゴリズム起動時や、ARの更新が深度推定の更新より速い場合などに、NULLになることがあります。

  • また、ARFrameの深度バッファは、そのバッファの生成に使用されるカメラ画像よりも数フレーム遅れています。そのため、生成されたフレームに最適な深度推定が得られるように、生成されたフレームのARCameraを使用して、常に深度を 補間 してください。

  • ARFrameの深度バッファは、必ずしも画面と一致しているわけではありません。以下の**アスペクト比** で説明するように、ARDKでは、未調整のバッファと、調整後、画面にクロップされたバッファの両方を取得するメソッドを使用できます。

視差のあるテクスチャを作成する

Depth.Data バッファのraw値は、 NearDistance から FarDistance の範囲で、各ピクセルの深度をメートル単位で表す浮動小数点数です。デバッグ目的で、深度バッファが画面にレンダリングされるのを確認する場合は、ARDepthManagerで ToggleDebugVisualization を有効にします。たとえば、以下のスクリプトの Start() メソッドで切り替えることができます。

using Niantic.ARDK.Extensions;

public ARDepthManager _depthManager;

void Start()
{
    // Enable debug visualization of depth buffer
    _depthManager.ToggleDebugVisualization(true);
}

深度バッファのテクスチャ表現を変更してカスタム画面出力に使用する必要がある場合は、 CreateOrUpdateTextureRFloat メソッドを呼び出して、0(遠いオブジェクト)から1(近いオブジェクト)の範囲で正規化された値を持つ視差テクスチャを作成することができます。または、 CreateOrUpdateTextureARGB32 を呼び出して、深度バッファからRGBテクスチャを作成することもできますが、独自の正規化関数を使用する必要があります。

Texture2D _disparityTexture;

void UpdateDisparityTexture(IDepthBuffer depth)
{
  float maxDisp = 1 / depth.NearDistance;
  float minDisp = 1 / depth.FarDistance;

  depth.CreateOrUpdateTextureARGB32
  (
    ref _disparityTexture,
    FilterMode.Point,
    depth => (1/depth - minDisp) / (maxDisp - minDisp)
  );
}

深度バッファを取得し、シェーダーを使用して画面にレンダリングする方法の例については、 中級チュートリアル: 深度テクスチャ をご参照ください。

なお、これらのメソッドでは、クロップや画面への調整が行われていないバッファのrawデータが返ります。対処方法については、次のセクションを参照してください。

アスペクト比

深度バッファのアスペクト比と解像度は、必ずしもデバイスのカメラや画面の解像度と一致するとは限りません(この値は、基礎となるディープラーニングモデルによって決まります)。 CopyToAlignedTextureARGB32 または CopyToAlignedTextureRFloat を使用すると、指定したカメラに合わせて寸法やアスペクト比が調整された深度テクスチャを取得することができます。これらのメソッドではピクセル単位でサンプリング処理が行われるため、速度が低下することがあります。または、AwarenessBufferProcessorから SamplerTransform を取得し、これをカスタムシェーダーで使用して、単一パスでクロッピングと調整を適用します。詳細については、 ARDKにおけるレンダリング の「アウェアネスバッファを画面に合わせて調整する」を参照してください。

アラインメントプロセスにより、クロッピングが生じる場合があります。クロッピングを行うと、データは常に水平方向に切り取られます。ARDKでは垂直方向に切り取るのではなく、以下のスクリーンショットのように左右に余白を取ることで、データの欠損を抑えます。シンプルなシェーダーで深度に応じてピクセルに色を付けていますが、側面の端に黒い列があるのは、その領域では深度データが利用できないためです。

../../../_images/texture_crop.jpeg

ARDepthManagerの使用

深度データを有効にして利用するためのプロセスを簡略化できるように、シーンに追加できる マネージャー 用意しています。使用方法については、ARDepthManagerのAPIリファレンスやコード内コメント、ツールヒントを参照してください。

深度情報とレンダリングパイプライン

カメラフィードデータのレンダリングに加えて、セッションが深度データを生成するよう設定されている場合は、ARDKのレンダーパイプラインがzバッファデータの生成も行います。そのため、対象シーンで深度生成を有効化する場合は、 ARDepthManager を使用するにしても、 ARSessionIsDepthEnabled に設定するにしても、シーンには ARRenderingManager が必須となります。 ARDepthManager を使う場合、 ARRenderingManager を追加したのと同じオブジェクトに ARDepthManager コンポーネントを追加する必要があります。

深度情報とモックモード

Unityエディターで深度データにアクセスする場合は、 モックモード を使用します。ARDKのダウンロードページ から入手できるARDKのモック環境パッケージに含まれる複数の既製のモック環境のうちのいずれかを使用することができます。モック環境パッケージをシーンにインポートし、 ARDK > バーチャルスタジオ ウィンドウのMockタブで、 Mock Scene(モックシーン) のドロップダウンから使用するプレハブを選択します。Unityのプレイモードで実行し、 ARSession で深度が有効になっている場合、プレハブはモックモードで自動的にインスタンス化され、プレハブメッシュの深度データが収集されます。

既成の環境がいずれもニーズに合わない場合は、自分でモック環境を作成することもできます。モックAR環境を作成するには、モック環境のジオメトリを指定してプロジェクトにプレハブを追加し、プレハブ内のルートGameObjectに MockSceneConfiguration コンポーネントを追加します。その後、 Mock Scene(モックシーン) ドロップダウンでプレハブを選択できます。

トラブルシューティング: モデル品質に関する留意点

ARDKの深度データは機械学習によって近似されているため、専用の深度センサーが搭載されていないデバイスでも動作しますが、その出力には本質的にノイズやバイアスが含まれます。

このGIFは、ノイズとバイアスがもたらす結果を示します。球体は静止しており、世界空間の地面のすぐ上に位置していますが、深度アルゴリズムが考える床のオクルージョンは、見る角度によって大きく異なり、フレームごとに大きく異なる場合もあります。

../../../_images/occlusion_noise.gif

深度機能を最大限に活用するには、以下のポイントを踏まえて体験を設計する必要があります。

  • 深度マップはカメラ画像よりかなり解像度が低いため、アップサンプリングされます。

  • 深度マップは、時間的な不整合、すなわち「ジッター」が発生します。ジッターは、カメラが動いておらず、シーンが変化していない場合にも発生することがあります。この既知の問題は、1フレームで予測するニューラルネットワークによるものです。安定性は、物体がモデルの最小範囲より近づくと下がる傾向があります。特に、ユーザーが足元の地面を見ている場合、安定性は低下します。

    • そのため、1フレームや1ピクセルの深度出力に依存することはお勧めできません。

  • 現在のモデルは、目線の高さにある物体の水平方向の深さを推定することに特化しているため、地面が完全に平面とは認識できない場合があり、また垂直方向の深さを推定することにも適していません。そのため、カメラが水平方向に向いている方が、深度推定の正確性は高くなります。

  • 深度マップは、軽度の照明の違いを含む色の変化に対して敏感に反応します。この現象は、ノイズの発生に大きく影響します。

  • 深度エッジはオブジェクトのエッジと完全に一致するとは限らないため、深度は実際よりも大きいか、太くなる可能性があります。

  • 深度推定を実行する前に、モデルをインターネット経由でダウンロードする必要があります(ローカルにキャッシュされていないことが前提)。

こちらもご覧ください

深度