2016年4月30日土曜日

OpenGLで影を付ける方法

はじめに


 物体と平面を考える。OpenGLにて物体の影を平面上に描画する最も簡単な方法は影行列なるものを使う方法である。ここでは、この影行列を求め、実装してみる。

影行列の導出


 同次座標系で考える。すなわち、ベクトルは全て4次元ベクトル、行列は$4\times4$行列である。物体上の任意の点を $\vec{p}$、光源の位置を $\vec{l}$、平面の法線ベクトルを $\vec{n}$、点 $\vec{p}$ を平面上に投影した点を $\vec{q}$ とおく(上図参照)。点 $\vec{q}$ は平面上にあるから \begin{equation} <\vec{n},\vec{q}> = 0 \label{eq_1} \end{equation} が成り立つ。ここで、$<\vec{n},\vec{q}>$ は内積 $\vec{n}^T \cdot \vec{q}$ を表す。これはスカラー量である。また、次式が成り立つ。 \begin{equation} \vec{q}-\vec{l} = t\;(\vec{p}-\vec{l}) \label{eq_2} \end{equation} $t$ は求めるべき実数である。式(\ref{eq_2})の両辺に$\vec{n}$をかけて \begin{equation} <\vec{n},\vec{q}>-<\vec{n},\vec{l}>=t<\vec{n},\vec{p}-\vec{l}> \end{equation} 式(\ref{eq_1})より \begin{equation} -<\vec{n},\vec{l}>=t<\vec{n},\vec{p}-\vec{l}> \end{equation} よって \begin{equation} t=\frac{-<\vec{n},\vec{l}>}{<\vec{n},\vec{p}-\vec{l}>} \label{eq_3} \end{equation} を得る。式(\ref{eq_2})に代入して \begin{eqnarray} \vec{q} &=&\vec{l} - \frac{<\vec{n},\vec{l}>}{<\vec{n},\vec{p}-\vec{l}>} (\vec{p}-\vec{l}) \\ &=&\frac{1}{<\vec{n},\vec{p}-\vec{l}>}\left[ -<\vec{n},\vec{l}>\vec{p}\;+<\vec{n},\vec{p}>\vec{l} \right]\\ &=&\frac{1}{<\vec{n},\vec{l}-\vec{p}>}\left[ <\vec{n},\vec{l}>\vec{p}\;-<\vec{n},\vec{p}>\vec{l} \right]\\ &=&\alpha\left[ <\vec{n},\vec{l}>\vec{p}\;-<\vec{n},\vec{p}>\vec{l} \right] \label{eq_4} \end{eqnarray} $\alpha\equiv 1/<\vec{n},\vec{l}-\vec{p}>$としたが、同次座標系を考えているので $\alpha$ は任意の実数として良い。 ここで、右辺第2項の第 $i$ 成分 $<\vec{n},\vec{p}>l_i$ を考える。 \begin{eqnarray} <\vec{n},\vec{p}>l_i &=&\sum_j\;n_j p_j l_i \\ &=&\sum_j\;l_i n_j p_j \\ &=&\left[\left(\vec{l}\cdot\vec{n}^{T}\right)\vec{p}\right]_i \end{eqnarray} 従って \begin{eqnarray} \vec{q} &=& \alpha\left[<\vec{n},\vec{l}>\vec{p}\;-\left(\vec{l},\vec{n}^{T}\right)\vec{p}\right] \\ &=& \alpha\left[ <\vec{n},\vec{l}>E-\left(\vec{l},\vec{n}^{T}\right)\right] \vec{p} \end{eqnarray} となる。$E$ は単位行列である。以上から \begin{eqnarray} \vec{q}&=&\alpha\;M\;\vec{p}\\ M&\equiv& <\vec{n},\vec{l}>E -\left(\vec{l},\vec{n}^{T}\right) \end{eqnarray} を得る。$M$が影行列である。

実装

影行列は207行目から222行目にかけて計算されている。$\alpha=1$ とした。また、床は $z=0$ ではなく $z=-0.005$ としてある。影をきれいに描画させるためである。

結果


開発環境


 Xcode Version 6.2

疑問


 $\alpha$ を負の数に取ると影が描画されない。何か勘違いしているのか?

0 件のコメント:

コメントを投稿