UnityのDepth
Zbufferに使用されるDepthの値はclip座標系におけるzの値を0~1に正規化したもの。カメラのnearにいると1,farにいると0になる。(多分)
現在のZbufferの値は_CameraDepthTextureから取得可能
Depthから距離を復元する場合、LinearEyeDepth、Linearly01Depthを使用する。これは渡されたDepthから"Nearからの距離"に変換する。Linear01は0~1に正規化しただけ。
code:Unity.cginc
// Z buffer to linear 0..1 depth
inline float Linear01Depth( float z )
{
return 1.0 / (_ZBufferParams.x * z + _ZBufferParams.y);
}
// Z buffer to linear depth
inline float LinearEyeDepth( float z )
{
return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w);
}
_ZBufferParamsはカメラのnearとfarの値が入っている。
https://scrapbox.io/files/645d1d427b5c0e001b335b1e.png
ただし、この方法による距離は"Near面からの距離"であり、カメラからの距離として得るには補正が必要である。わかりやすい資料としてはkurotoriさんの記事が分かりやすい。これを用いれば3次元座標の復元が可能になる。
何故だかはわからないけどkurotoriさんの方法でも画面端ではゆがむことがある。さらなる補正としては keijiroさんのコードがある。何をやっているのかさっぱりわからない
code: InverseProjection.shader
inline float4 CalculateFrustumCorrection()
{
float x1 = -PM._31/(PM._11*PM._34);
float x2 = -PM._32/(PM._22*PM._34);
return float4(x1, x2, 0, PM._33/PM._34 + x1*PM._13 + x2*PM._23);
}
inline float CorrectedLinearEyeDepth(float z, float B)
{
return 1.0 / (z/PM._34 + B);
}