ARCore Depth API for Unity でdepth値をShaderで扱う
ARCore v1.18.0がリリースされ、Depth APIが使えるようになりました。 早速ハックしてみたいと思います(笑)
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データが格納されます。
Shader内でdepth値を求める
ここまでの解説をまとめると、ARCore Depth API for Unityのdepthデータ値の表現とRGB565テクスチャへのマッピングは下記となっています。
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です(笑)
まとめ
ARCore Depth API for Unity で取得できるdepthフォーマットとShader内でのデータ変換について書きました。
しかし、このぼんやりとしたdepthはどうにかならないんでしょうか。。w (フィルタ無しのRAWデータ触りたい)