🐼
UnityのいろいろなDepthTextureの使い方
はじめに
UnityのシェーダーでDepthTextureを使っていて調べたことのまとめ。
各種DepthTextureの内容からメートルの距離を取得する方法と使う時の注意点。
いろいろなDepthTextureからメートルの距離を取得する
- _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);
...
}
- カメラ(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);
...
}
- カメラ(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にリニアな値が入っている。
// !!! 指摘あったら教えてください。🐼
...
}
- Stereoなカメラで撮ったDepthTextureの場合
調べたらそのうち書きます。
たぶん、sampler2Dでなくsampler2DArrayになる。
DepthTextureから取得したメートル距離の注意点
おそらく各画素のワールド座標までの距離と比較する使い方をすると思います。
その際の注意点。
以下図のように、カメラからワールド座標までの距離PE
とDepthTextureから取得できる距離DE
は向きが違います。
PE
は wPos - _WorldSpaceCameraPos
で、DE
は#1で取得できますが、
そのまま比較しても画素の座標がDepthより近いかどうかはわかりません。
以下図のようにP'またはE'を求めて、PEとD'E
またはP'EとDE
を比較しましょう。
その際必要になるDEの単位ベクトルはカメラの向きであり、normalize(-UNITY_MATRIX_V[2].xyz)
で取得できます。
プロジェクターの場合はEの位置もDEベクトルも取得できないのでマテリアルにプロパティ経由で渡しましょう。
参考
Discussion