[Unity] Depthについてあれこれ
はじめに
これからまた情報を付加させていくつもりですが,現時点でも何かの参考になればと思っております.
間違っている点や補足などがありましたら教えてください.
パースペクティブ射影変換(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}
(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)
実際に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} \\
実際に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;
}
#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による違い
fixed4 frag(v2f i) : SV_Target
{
half depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
depth = Linear01Depth(depth);
return depth;
}
Author And Source
この問題について([Unity] Depthについてあれこれ), 我々は、より多くの情報をここで見つけました https://qiita.com/keito_takaishi/items/c280f5fa627529b603b8著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .