1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Posted at

はじめに

これからまた情報を付加させていくつもりですが,現時点でも何かの参考になればと思っております.
間違っている点や補足などがありましたら教えてください.

パースペクティブ射影変換(ProjectionMatrix)

DirectX

(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成分に関して計算してみると,

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

Depth

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

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

そして,グラフにしてみるとこんな感じになります(横軸がビュー空間のdepth, 縦が変換後のdepth)
bandicam 2020-06-02 01-14-27-561.jpg

実際に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について

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

Far_Topについて

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

(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成分に関して計算してみると

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

Depth値

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

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

bandicam 2020-06-02 01-42-48-979.jpg

実際に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に関しては前の値が再代入されています.

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

# 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/

線形にしたい場合

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

GrapchisAPIによる違い

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?