【Unity】【シェーダ】描画対象のピクセルに対応する深度テクスチャから深度値を取得する

描画対象のピクセルに対応する深度テクスチャから深度値を取得する方法です。

Unity2019.2.10

ソースコード

まずいきなりですがシェーダの全文を掲載します。

Shader "DepthFromTexture"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 projPos : TEXCOORD0;
            };

            sampler2D _CameraDepthTexture;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.projPos = ComputeScreenPos(o.vertex);
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {
                return LinearEyeDepth(tex2Dproj(_CameraDepthTexture, i.projPos).r);
            }
            ENDCG
        }
    }
}

またプラットフォームによっては深度テクスチャが生成されていない場合があるので、
CameraのdepthTextureModeを下記のように変更しておきます。

using UnityEngine;

public class DepthTexture : MonoBehaviour {


    void Start () {
        GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
    }
}

説明

さて上記のソースコードですが、基本的にはUnityが生成する深度テクスチャをサンプリングしているだけです。
このテクスチャは_CameraDepthTextureという変数を定義することでそこから取得できます。
これに関しては以下の記事にまとめていますので必要に応じて参照してください。

light11.hatenadiary.com

また深度テクスチャはスクリーンに対してマッピングされるため、
ComputeScreenPosとtex2Dprojを用いてサンプリングすべきUV座標を求めています。
これに関しては以下の記事にまとめていますので、必要に応じて参照してください。

light11.hatenadiary.com

このようにして求めた深度テクスチャの値は、LinearEyeDepth関数で深度値に変換できます。
またもし0~1の値として取得したい場合は、代わりにLinear01Depth関数を使用します。
このあたりの詳細も上記の記事(カメラから見た深度値の方)にまとめています。

関連

light11.hatenadiary.com

light11.hatenadiary.com