機械学習基礎理論独習

誤りがあればご指摘いただけると幸いです。数式が整うまで少し時間かかります。リンクフリーです。

勉強ログです。リンクフリーです
目次へ戻る

透視深度に関する考察

はじめに

本記事は、以前書いた透視投影変換行列 - 導出その2の投影に関する部分が分かりにくく疑問点が残ると思ったので、それを解決するために書きました。
本記事の大きな流れは、「標準的な透視投影について」、「透視投影変換行列についての考察」、「透視深度がzの逆数に比例しても本当に良いのか」という透視投影を掘り下げた内容となっております。
ちなみに、「透視深度」とは、正規化デバイス座標系のz値の事です。
「深度」という言葉が使われているのは、恐らく正規化デバイス座標系のz軸が視線方向と一致しているためでしょう。

本記事は、本は参考にしましたが、自身の考察によるところも大きいので、予めご了ください。
なお、座標系は左手座標系で説明します。本記事で扱うグラフィックスライブラリは今のところOpenGLまたはWebGLなので。

標準的な透視投影について知る

CGにおける透視投影ではなく、まずは「標準的な透視投影」について考えてみます。
原点を投影中心とし、平面 z=d を投影面とします。
P(x_1,y_1,z_1) の投影像を Q(x_2,y_2,z_2) とします。(x_2,y_2,z_2) は以下のように求まります。

\begin{eqnarray}
\begin{pmatrix}
x_2\\y_2\\z_2
\end{pmatrix}
=
\begin{pmatrix}
\dfrac{dx_1}{z_1}\\\dfrac{dy_1}{z_1}\\d
\end{pmatrix}\tag{1}
\end{eqnarray}

(1) を同次座標にし、行列を使って表します。

\begin{eqnarray}
\begin{pmatrix}
\dfrac{dx_1}{z_1}\\\dfrac{dy_1}{z_1}\\d\\1
\end{pmatrix}
\sim
\begin{pmatrix}
dx_1\\dy_1\\dz_1\\z_1
\end{pmatrix}
=
\begin{pmatrix}
d & 0 & 0 & 0\\
0 & d & 0 & 0\\
0 & 0 & d & 0\\
0 & 0 & 1 & 0
\end{pmatrix}
\begin{pmatrix}
x_1\\y_1\\z_1\\1
\end{pmatrix}\tag{2}
\end{eqnarray}

(2) の行列は、投影を表す行列なので、変換後のz座標が d になります。
勿論これでよいのですが、z座標がすべて d になってしまうので、z座標の情報が失われることになります。
そうすると、zバッファを使った陰面処理ができなくなります。
例えば、以下のように行列を変更すると、zの同次座標の値はそのまま保持されます。まあ標準座標ではzは1固定になってしまいますが。

\begin{eqnarray}
\begin{pmatrix}
d & 0 & 0 & 0\\
0 & d & 0 & 0\\
0 & 0 & 1 & 0\\
0 & 0 & 1 & 0
\end{pmatrix}\tag{3}
\end{eqnarray}

透視投影変換行列についての考察

冒頭で書いた通り、ここで示すのは、透視投影のためにせん断変換をした後、投影を行い、最後に拡大縮小をしますが、その「投影」の箇所の説明です。
もっと端的に言うと、{\bf M}_{projection} の導出、特に透視深度について詳しく説明したいと思います。

さて、せん断後は、前方面のxy中心は原点を通ります。
この時の視体積の前方面のxy座標は、-\dfrac{right+left}{2}\leq x \leq\dfrac{right+left}{2},\ -\dfrac{top+bottom}{2}\leq y \leq\dfrac{top+bottom}{2} であり、
z座標は、-near\leq z\leq-farです。
この錐台である視体積を直方体にする変換が求める {\bf M}_{projection} なわけです。
まずは、xy座標についての変換を考えます。
後方面が前方面と一致しないので、視体積が直方体が錐台になって歪んでいるわけです。これを直してやりましょう。
この変換は、前方面に視体積内の点を投影したxy座標を採用すればよいことになります。
よって、変換前のxyzを x,y,z とし、変換後のxy座標を x',y' とすれば、以下のようになります。

\begin{eqnarray}
&&x'=-\frac{near}{z}x\tag{4}\\
&&y'=-\frac{near}{z}y\tag{5}
\end{eqnarray}
変換後のz座標を一旦 z'=ax+by+cz+d とだけしておきます。一旦、行列で表すためです。
変換後の同次座標は以下のようになります。
\begin{eqnarray}
\begin{pmatrix}
 -\dfrac{near}{z}x\\
 -\dfrac{near}{z}y\\
 z'\\
 1
\end{pmatrix}
\sim
\begin{pmatrix}
 -near\cdot x\\
 -near\cdot y\\
 zz'\\
 z
\end{pmatrix}
=
\begin{pmatrix}
 -near\cdot x\\
 -near\cdot y\\
 z\left(ax+by+cz+d\right)\\
 z
\end{pmatrix}
=
\begin{pmatrix}
 -near & 0 & 0 & 0\\
 0 & -near & 0 & 0\\
 a & b & c & d\\
 0 & 0 & 1 & 0\tag{6}
\end{pmatrix}
\end{eqnarray}
(6) の3行目が a,b,c,d になっていますが、これはとりあえず、z'=ax+by+cz+d とおいたためです。

a,b,c,d について考えていきましょう。
z' って変換前のxy座標の影響って受けないと考えるのが自然ですよね。よって、a=0,b=0です。
行列に反映させると、以下のようになります。

\begin{eqnarray}
\begin{pmatrix}
 -near & 0 & 0 & 0\\
 0 & -near & 0 & 0\\
 0 & 0 & c & d\\
 0 & 0 & 1 & 0\tag{7}
\end{pmatrix}
\end{eqnarray}
変換行列が (7) のときの同時座標のzは z'=cz+d であり、標準座標は z'=c+\dfrac{d}{z} となります。
このとき dd\not=0 です。
なぜなら、d=0 のとき、標準座標のzは z'=c とすべてのzが同じ値に変換されてしまいます。
そうだとすると、この後に行われるZバッファによる陰面処理ができないですよね。ということで、 d\not =0 です。
ということは、c が平行移動成分で、d/z と変換前のzに反比例していることが分かります。
この類の書籍を見ると、「透視深度のzは反比例する」とさらっと書いてあることが多いです。
えっ、zは変換されると元のzに反比例するの?はい、そうです。
zは反比例するけれども、その後の処理(陰面処理など)を考えるとzの大小関係さえ保ってさえいればよいので、「zは変換されると元のzに反比例」で問題ないのかなって思います。
ということで、c,d をいい感じに求めていきます。
先に d を求めます。c が邪魔なので一旦 c=0とします。
仮に d=1 としてみます。このときzの標準座標は、z'=\dfrac{1}{z} となります。
これにより z=-nearz'=\dfrac{1}{-near} となり、z=-farz'=\dfrac{1}{-far} となり、\dfrac{1}{-near}\geq\dfrac{1}{-far} なので、zの大小関係が逆転してしまいます。
大小関係が逆転しないのように-(マイナス)をつけ、d=-1 とすれば良さそうです。
d=-1 のとき z=-nearz'=\dfrac{1}{near} となり、z=-farz'=\dfrac{1}{far} となるので、視体積のzの長さは \dfrac{1}{far}-\dfrac{1}{near}=\dfrac{near- far}{far\cdot near} となります。
ここで、dfar\cdot near 倍すると、変換前の視体積のzの長さ同じなので、最終的に d=-far\cdot near とします。
d=-far\cdot near のとき、 z=-nearz'=far となり、z=-farz'=near となります。
あとは、視体積のzの中心 \dfrac{far+near}{2} が原点に来るように平行移動します。よって、c=-\dfrac{far+near}{2} となります。
以上より、a,b,c,da=0,\ b=0, \ c=-\dfrac{far+near}{2}, d=-far\cdot near と求まりましたので、行列に反映させると、以下のようになります。
\begin{eqnarray}
\begin{pmatrix}
 -near & 0 & 0 & 0\\
 0 & -near & 0 & 0\\
 0 & 0 & -\dfrac{far+near}{2} & -far\cdot near\\
 0 & 0 & 1 & 0\tag{8}
\end{pmatrix}
\end{eqnarray}
変換後の標準座標に変化が無いように、式 (8) を少しきれいにします。
具体的には、4行3列目の成分に -1 を掛けます。そうすると、標準座標に直すときにこの -1 が全ての成分にかかるので、全成分に-1を掛けます。
\begin{eqnarray}
\begin{pmatrix}
 near & 0 & 0 & 0\\
 0 & near & 0 & 0\\
 0 & 0 & \dfrac{far+near}{2} & far\cdot near\\
 0 & 0 & -1 & 0\tag{9}
\end{pmatrix}
\end{eqnarray}

この式 (9)透視投影の記事の式 (15) と一致していることが分かります。
以上が、投影の説明です。

透視深度がzの逆数に比例しても本当に良いのか(この項目は書くかどうか微妙)

バイス座標系の線形補間は、ビュー座標系の逆数が線形補間されているってことをここで書こうと思っています。(書くかどうか悩んでいるので、ここに備忘録として記載。)
逆数が線形補間されるんだから、透視深度はビュー座標系のzに反比例しても悪くないぞってことを書きたい。
該当文献ページは
ゲームプログラミングのための3Dグラフィックス数学 p94-97
コンピュータグラフィックスの基礎 p60-p62

最後に

「標準的な透視投影について知る」の項目は不要だったかなって思います。

参考文献

ゲームプログラミングのための3Dグラフィックス数学 p94-97
コンピュータグラフィックスの基礎 p60-p62

目次へ戻る