つくるの大好き。

つくるのが大好きな人の記録。

ARCore Depth API for Unity でdepth値をShaderで扱う

ARCore v1.18.0がリリースされ、Depth APIが使えるようになりました。 早速ハックしてみたいと思います(笑)

f:id:peugeot-106-s16:20200628225056j:plain

ARCore Depth API for Unityの説明はこちら developers.google.com

Depthデータへのアクセス

https://developers.google.com/ar/develop/unity/depth/overview#depth-maps

Frame.CameraImage.UpdateDepthTexture() から取得することができます。 Texture2Dでの提供です。

なお、CPUでデータを扱いたい場合はこちらが使えます。
https://github.com/google-ar/arcore-unity-sdk/blob/fbc21676ef0bb305c775fa3be593b8c46a62c211/Assets/GoogleARCore/SDK/Scripts/Api/Wrappers/FrameApi.cs#L352-L353

Depthデータのフォーマット

https://developers.google.com/ar/develop/unity/depth/overview#depth-map-format

ARCore Depth APIのデータフォーマットはDEPTH16形式と呼ばれるもので、13bitのdepth値(mm単位)と3bitのconfidence値(信頼性)を組み合わせた16bit値です。
ただしARCore Depth APIではconfidenceは常に0がセットされるようなので取得できないようです。

https://developer.android.com/reference/android/graphics/ImageFormat#DEPTH16

Textureデータのフォーマット

Frame.CameraImage.UpdateDepthTexture() で取得できるTextureのフォーマットはRGB565形式で16bitデータが格納されます。

https://github.com/google-ar/arcore-unity-sdk/blob/fbc21676ef0bb305c775fa3be593b8c46a62c211/Assets/GoogleARCore/SDK/Scripts/Api/Wrappers/FrameApi.cs#L269-L270

Shader内でdepth値を求める

ここまでの解説をまとめると、ARCore Depth API for Unityのdepthデータ値の表現とRGB565テクスチャへのマッピングは下記となっています。 f:id:peugeot-106-s16:20200628222732p:plain

RGB565テクスチャのピクセルはr, g, bのフィールドからそれぞれ範囲(0.0-1.0)の数値として取得できるので、整数値に変換し、ビットシフトして合計すれば元の16bit値を復元することができます。

抜粋するとこんな感じです。

#define ARCORE_MAX_DEPTH_MM 8191.0
#define ARCORE_FLOAT_TO_5BITS 31        // (0.0, 1.0) -> (0, 31)
#define ARCORE_FLOAT_TO_6BITS 63        // (0.0, 1.0) -> (0, 63)
#define ARCORE_RGB565_RED_SHIFT 2048    // left shift 11 bits
#define ARCORE_RGB565_GREEN_SHIFT 32    // left shift 5 bits

float depth = (pixel.r * ARCORE_FLOAT_TO_5BITS * ARCORE_RGB565_RED_SHIFT)
    + (pixel.g * ARCORE_FLOAT_TO_6BITS * ARCORE_RGB565_GREEN_SHIFT)
    + (pixel.b * ARCORE_FLOAT_TO_5BITS);
depth = min(depth, ARCORE_MAX_DEPTH_MM);
  • Rを0-31範囲に変換し、11bitシフトする
  • Gを0-64範囲に変換し、5bitシフトする
  • Bを0-31範囲に変換する
  • 3つの数値を足し合わせる
  • ARCore Depth API では8メートルまでの距離を扱うことができるので8191を超えた値は8191に収める

とすることで、depth値を求めることができます。

なお、実はこの処理はARCoreDepth.cginc 内で ArCoreDepth_GetMeters() として用意されているので、普通はこちらを使えばOKです(笑)

https://github.com/google-ar/arcore-unity-sdk/blob/fbc21676ef0bb305c775fa3be593b8c46a62c211/Assets/GoogleARCore/SDK/Materials/ARCoreDepth.cginc#L45-L55

まとめ

ARCore Depth API for Unity で取得できるdepthフォーマットとShader内でのデータ変換について書きました。

しかし、このぼんやりとしたdepthはどうにかならないんでしょうか。。w (フィルタ無しのRAWデータ触りたい)