[Unity] Depthについてあれこれ

# はじめに
これからまた情報を付加させていくつもりですが，現時点でも何かの参考になればと思っております．
間違っている点や補足などがありましたら教えてください．
# パースペクティブ射影変換(ProjectionMatrix)
## DirectX
```math
(x, y, z, 1) 
\begin{pmatrix}
\frac{H}{W}\cot(\frac{\theta}{2}) & 0 & 0 & 0 \\
0 & \cot(\frac{\theta}{2}) & 0 & 0 \\
0 & 0 & fz \cdot \frac{1}{fz - nz} & 1 \\
0 & 0 & fz \cdot \frac{-nz}{fz - nz} & 0 \\
\end{pmatrix}
```

上の式に関してz成分に関して計算してみると，

```math
\frac{1}{z} (\frac{fz\cdot z}{fz-nz} - \frac{fz \cdot nz}{fz - nz}) \\
\frac{fz}{z} \frac{z - nz}{fz - nz}

```

### Depth
具体的に数値を当てはめてみると

```math
fz = 10 \\
fz = 1 \\
\frac{10}{9} - \frac{10}{9z} \\
```

そして，グラフにしてみるとこんな感じになります(横軸がビュー空間のdepth, 縦が変換後のdepth)
![bandicam 2020-06-02 01-14-27-561.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184790/9a6d5408-4be0-51ab-e8fe-27855ad1e40b.jpeg)


実際にNearClip(z = 1)を代入してみると値が0，FarClip(z = 10)を代入してみると値が1になっていることからDepthの範囲が0 ~ 1に収収まっていることが確認出来ました．

### x,y値
yについて値を具体的に考えてみます．
$\frac{\theta}{2} = 30$とし，$near=2.0$, $far=10.0$としたとき，それぞれの地点でのyのtopの高さは$y_{NearTop} = \frac{2}{\sqrt 3}$， $y_{FarTop} = \frac{10}{\sqrt 3}$ となります．(tanを使用することで計算出来ます)

それに対して上に示した行列を作用させると，

`Near_Topについて`

```math
y'_{NearTop} = \frac{ \frac{2}{\sqrt 3} \cot{\frac {\pi}{6}}}{nz} \\
y'_{NearTop} = \frac{2}{nz} \\
y'_{NearTop} = 1.0
```

`Far_Topについて`

```math
y'_{FarTop} = \frac{ \frac{10}{\sqrt 3} \cot{\frac {\pi}{6}}}{fz} \\
y'_{NearTop} = \frac{10}{fz} \\
y'_{FarTop} = 1.0
```

よってどちらも1.0になっています．他のbottom, right, leftについても同様に計算していけば正規化(-1.0 ~ 1.0)させれていることが確認できるかと思います．
またw除算する前のタイミングでは`-w ~ w`となってます．
## OpenGL

```math
(x, y, z, 1) 
\begin{pmatrix}
\frac{2near}{right - left} & 0 & 0 & 0 \\
0 & \frac{2near}{top - bottom} & 0 & 0 \\
0 & 0 & -\frac{fz +nz}{fz - nz} & -1 \\
0 & 0 & -2 \cdot \frac{fz \cdot nz}{fz - nz} & 0 \\
\end{pmatrix}
```

上の式に関してz成分に関して計算してみると

```math
(\frac{z \cdot (fz + nz) - 2fzfn}{fz-nz}) \frac{1}{z}
```


### Depth値
具体的に数値を当てはめてみると

```math
fz = 10 \\
fz = 1 \\
\frac{11}{9} - \frac{20}{9z} \\
```

![bandicam 2020-06-02 01-42-48-979.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184790/37701bb5-d79d-3bf8-12f3-2ce865feb54f.jpeg)


実際にNearClip(z = 1)を代入してみると値が-1，FarClip(z = 1)を代入してみると値が1になっていることからDepthの範囲が0 ~ 1に収収まっていることが確認出来ました．

ここまでで分かったこととしてはDirectXでは**Depthの値が0.0 ~ 1.0**, OpenGLでは**Depthの値が-1.0 ~ 1.0**, といういことです．


# LinearDepth



# UnityObjectToClipPos
`UnityObjectToClipPos`ではx,yは`-w ~ w`, zは`0 ~ w`(GraphicsAPIによっては`-w ~ w`)の範囲までの計算が行われ，w除算が行われていない状態です．


# ComputeScreenPos
入ってくる値としては`UnityObjectToClipPos`によって変換されたw除算される前の値です．
x, yについて`0 ~ w`に変換している．z, wに関しては前の値が再代入されています．
 
```c
inline float4 ComputeNonStereoScreenPos(float4 pos) {
    float4 o = pos * 0.5f;
    o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;
    o.zw = pos.zw;
    return o;
}
``` 


# _CameraDepthTexture
0.0 ~ 1.0までの値が格納されているTexture
https://soramamenatan.hatenablog.com/entry/2019/11/10/133420d



# COMPUTE_EYEDEPTH

```c
#define COMPUTE_EYEDEPTH(o) o = -UnityObjectToViewPos(v.vertex).z

inline float3 UnityObjectToViewPos(in float3 pos)
{
    return mul(UNITY_MATRIX_V, mul(unity_ObjectToWorld, float4(pos, 1.0))).xyz;
}
```

通常Unityは左手座標系(z軸の奥の方がプラス)なのですが，カメラ座標系にしたときは右手座標系(z軸の手前がプラス)になります．その為，今回-1.0をかけている理由としてはDepthの値(正)を必要とするためです．

参考：https://tech.drecom.co.jp/knowhow-about-unity-coordinate-system/

# 線形にしたい場合

```c
fixed4 frag(v2f i) : SV_Target
{
    half depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
    depth = Linear01Depth(depth);
    return depth;
}
```

# GrapchisAPIによる違い
https://docs.unity3d.com/ja/current/Manual/SL-PlatformDifferences.html６