🐼

UnityのいろいろなDepthTextureの使い方

2024/03/21に公開

はじめに

UnityのシェーダーでDepthTextureを使っていて調べたことのまとめ。
各種DepthTextureの内容からメートルの距離を取得する方法と使う時の注意点。

いろいろなDepthTextureからメートルの距離を取得する

  1. _CameraDepthTextureの場合
//宣言
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);

fixed4 frag(v2f i): SV_Target
{
    ...
    float depth = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos));
    //メートルの値
    float depthMetres = LinearEyeDepth(depth);
    ...
}
  1. カメラ(Perspective)で撮ったDepthTextureの場合
Properties{
    ...
    _DepthTex ("DepthTex", 2D) = "black" { }
}

(以下Passの中)

//宣言
uniform sampler2D _DepthTex;

//DepthTextureの値をメートルにしてくれるやつ
inline float CustomLinearEyeDepth(float depth, float near, float far)
{
    /*
    DepthTextureの値が[0:近い、1:遠い]の時
    float x = 1 - far / near;
    float y = far / near;
    float z = x / far;
    float w = y / far;
    */
    
    //DepthTextureの値が[1:近い、0:遠い]の時
    float x = -1 + far / near;
    float y = 1;
    float z = x / far;
    float w = 1 / far;

    return 1.0 / (z * depth + w);
}

fixed4 frag(v2f i): SV_Target
{
    ...
    float depth = tex2Dproj(_DepthTex, UNITY_PROJ_COORD(i.projPos));
    float near, far = DepthTextureを撮ったカメラのnear, far;

    //メートルの値
    float depthMetres = CustomLinearEyeDepth(depth, near, far);
    ...
}
  1. カメラ(Orthographic)で撮ったDepthTextureの場合
Properties{
    ...
    _DepthTex ("DepthTex", 2D) = "black" { }
}

(以下Passの中)

//宣言
uniform sampler2D _DepthTex;

fixed4 frag(v2f i): SV_Target
{
    ...
    float depth = tex2Dproj(_DepthTex, UNITY_PROJ_COORD(i.projPos));
    float near, far = DepthTextureを撮ったカメラのnear, far;

    //メートルの値(DepthTextureの値が[1:近い、0:遠い]の時)
    float depthMetres = (far - near) * (1 - depth) + near;

    // !!! 自信ないけど、Orthographicだと動作確認するとdepthにリニアな値が入っている。
    // !!! 指摘あったら教えてください。🐼
    ...
}
  1. Stereoなカメラで撮ったDepthTextureの場合
    調べたらそのうち書きます。
    たぶん、sampler2Dでなくsampler2DArrayになる。

DepthTextureから取得したメートル距離の注意点

おそらく各画素のワールド座標までの距離と比較する使い方をすると思います。
その際の注意点。

以下図のように、カメラからワールド座標までの距離PEとDepthTextureから取得できる距離DEは向きが違います。

PEwPos - _WorldSpaceCameraPosで、DE#1で取得できますが、
そのまま比較しても画素の座標がDepthより近いかどうかはわかりません。

以下図のようにP'またはE'を求めて、PEとD'EまたはP'EとDEを比較しましょう。

その際必要になるDEの単位ベクトルはカメラの向きであり、normalize(-UNITY_MATRIX_V[2].xyz)で取得できます。

プロジェクターの場合はEの位置もDEベクトルも取得できないのでマテリアルにプロパティ経由で渡しましょう。

参考

https://qiita.com/kajitaj63b3/items/3bf0e041f6be4fad164b
https://murasame-labo.hatenablog.com/entry/2017/08/05/012011
https://blog.nekoteam.com/archives/153

Discussion