Нижеизложенный материал, вероятно, знаком, или даже хорошо известен, программистам, имевшим опыт работы с OpenGL, между тем, я счел уместным напомнить о модели oblique frustum, отчасти наблюдая (и разделяя) интерес читателей Хабра к вопросам OpenGL и в целом трёхмерного моделирования, отчасти из несогласия с позицией некоторых разработчиков вроде «…чтобы это использовать, вовсе не обязательно разбираться в том, как работает матрица проекции», отчасти из уважения и благодарности к Эрику Ленгелу|Eric Lengyel, изобретательная мысль которого обогатила приемы работы в среде OpenGL.

Если в моделируемых вами сценах присутствуют зеркальные отражения, и вы подзабыли или не слышали про «oblique frustum», то возможно, что эта статья не будет для вас бесполезной.

Несмотря на то, что я, вслед за Эриком Ленгелом, более придерживался при изложении материала представлений OpenGL, все последующие рассуждения легко распространяются на любые другие системы трёхмерного моделирования.

Reflections

Отражения в 3D–сценах


В случае, когда в 3D-сценах присутствуют отражающие поверхности, обычная практика получения отражения заключается в рендеринге сцены с использованием вспомогательной камеры вида, которая сама является отражением основной камеры вида плоскостью отражающей поверхности.

arbitrary camera


Рис. 1. Верхняя камера является основной камерой, через которую происходит рендеринг сцены, содержащей отражающую поверхность. Нижняя камера является вспомогательной камерой, предназначенной для рендеринга отражения. Ось X направлена к наблюдателю для обеих пирамид видимости (в принятых для OpenGL представлениях), и очевидно, что координатная система для камеры, осуществляющей рендеринг отражения, является левосторонней.

При рендеринге отражения вспомогательной камерой (камерой отражения), может оказаться, что часть объектов, расположенных между наблюдателем и отражающей поверхностью, оказывается в результирующем рендере, образуя нежелательные артефакты в изображении. Чтобы отсечь нежелательную часть отраженной сцены с финального рендера, программист ограничивает наблюдаемую из камеры отражения часть объема трёхмерной сцены воображаемой поверхностью, используя различные приемы для того, чтобы прервать визуализацию сцены за границей этой поверхности.

Можно воспользоваться инструкцией „discard” для фрагментного шейдера или ей подобными, специфическими для отдельных реализаций рендеринга в общей идеологии 3D–моделирования ( например „kill” в AGALMiniAssembler), однако, если нам желательно решение универсальное, одинаково хорошо работающее на любом процессоре, то стоит обратить внимание на технику, предложеную Эриком Ленгелом.

Идея Эрика Ленгела заключалась в том, чтобы модифицировать проекционную матрицу таким способом, чтобы ближний план пирамиды видимости стал как раз своего рода секущей плоскостью, отделяющей нежелательный в конечном рендере объем основной сцены.

Для дальнейшего уместно напомнить элементарные представления аналитической геометрии.

Плоскость в пространстве


Для удобства изложения, будем придерживаться следующих обозначений:

\begin{center}
\begin{array}{|rlc}
\textbf{для точек и векторов:} & \vec{A}, \vec{P}\\multicolumn{2}{|l}{\textit{отличая их }\mathit{w} \textit{-координатой в однородном представлении,}}\\multicolumn{2}{|l}{\textit{координатную запись заключаем в угловые скобки }\langle ,,, \rangle}\\[0.3em]
\textbf{для матриц:} & \mathbf{M}, \mathbf{P} \\textbf{транспонированная матрица:} &\mathbf{M}^\mathrm{T} \\textbf{обратная матрица:} & \mathbf{M}^{-1} \\textbf{знак } x:  & sgn(x) =
  \begin{cases}
    1,       & \quad \text{if } x>0\    0,       & \quad \text{if } x=0\    -1,  & \quad \text{if } x<0
  \end{cases}\\textbf{длина вектора:} & \|\vec{P}\| \\textbf{скалярное произведение векторов:} & \vec{Q}\cdot\vec{P} \\end{array}
\end{center}

Плоскость


Для любой пространственной 3D-точки \vec{P} и вектора \vec{N}, совокупность 3D-точек \vec{Q}, отличных от \vec{P}, удовлетворяющих уравнению \vec{N}\cdot(\vec{Q}-\vec{P}) определяет плоскость, при этом точка \vec{P} является одной из принадлежащих этой плоскости точек, а вектор \vec{N} является её вектором нормали.

Plane

Рис. 2. Плоскость полностью определяется принадлежащей ей точкой \vec{P} и нормаль-вектором \vec{N}.

Уравнение плоскости часто записывается следующим выражением:

Ax+By+Cz+D=0,

где \mathit{A, B} и \mathit{C} есть \mathit{x, y, z} компоненты нормального вектора \vec{N}, причем D=-\vec{N}\cdot\vec{P}. Значение |D|/\|\vec{N}\| равно расстоянию до плоскости от начала координат (помним, что компоненты нормального вектора, деленные на его длину, есть направляющие косинусы единичного вектора нормали плоскости).

В случае нормализованного вектора нормали, выражение

d=\vec{N}\cdot\vec{Q}+D,

может быть использовано, для нахождения расстояния от плоскости до произвольной точки \vec{Q}. Если d=0, \vec{Q} лежит в плоскости. В случае, если d>0, точка \vec{Q} находится с положительной стороны плоскости, т.е. со стороны нормального вектора плоскости, при d<0, точка \vec{Q} располагается в стороне от плоскости, в направлении противоположном направлению нормального вектора плоскости \vec{N}.
Удобно записать плоскость четырехмерным вектором. Коротко уравнение плоскости запишется так: \langle \vec{N}, D \rangle. Очевидно, что для произвольной точки \vec{Q}, имеющей в однородных 4-хмерных координатах \mathit{w}-координату равную 1, Выражение (2) может быть переписано как d=\vec{L}\cdot\vec{Q}, где \vec{L}=\langle \vec{N}, D \rangle и точка \vec{Q} лежит в плоскости, если \vec{L}\cdot\vec{Q}=0.

Преобразование плоскости


Для понимания особенности пространственного преобразования плоскости, потребуется некоторое внимание уделить преобразованию нормального вектора. При пространственном преобразовании полигональной модели, вектора касательные к поверхности полигонов и вектора нормальные ведут себя неодинаково. Вектор касательный часто можно представить как разницу между двумя преобразованными вершинами, т.е. между двумя естественным образом преобразованными точками, и, вследствие этого, характер преобразованного вектора совпадает с нашими ожиданиями. Но, в общем случае пространственного преобразования, матрица \mathbf{M} которого не является ортогональной, прямое применение матрицы преобразования к нормальному вектору приведет к тому, что этот вектор перестанет быть нормальным – перпендикулярным к поверхности полигона.

Поскольку вектор касательный \vec{T} и вектор нормальный \vec{N}, принадлежащие одному полигону, должны оставаться перпендикулярными, для скалярного произведения преобразованных векторов \vec{T}{^'} и \vec{N}{^'} должно выполняться то же условие что и для исходных векторов: \vec{T}{^'}\cdot\vec{N}{^'}=0. Совершим несколько простых алгебраических операций, чтобы прояснить природу нормального вектора:

если \mathbf{M} – 3х3-матрица трансформации пространства (для случая касательного и нормального векторов пространственные перемещения несущественны), и \vec{T}{^'}=\mathbf{M}\vec{T}, то зададимся целью найти матрицу преобразования \mathbf{G} для \vec{N}, такую, чтобы выполнялось

\vec{N}{^'}\cdot\vec{T}{^'}=(\mathbf{G}\vec{N})\cdot(\mathbf{M}\vec{T})=0,

вспомним, что умножение векторов можно записать и следующим образом (совершенно равнозначным):

(\mathbf{G}\vec{N})\cdot(\mathbf{M}\vec{T})=(\mathbf{G}\vec{N})^\mathrm{T}(\mathbf{M}\vec{T})=\vec{N}^\mathrm{T}\mathbf{G}^\mathrm{T}\mathbf{M}\vec{T},

Поскольку \vec{N}^\mathrm{T}\vec{T}=0, выражение \vec{N}^\mathrm{T}\mathbf{G}^\mathrm{T}\mathbf{M}\vec{T}=0 выполняется, если \mathbf{G}^\mathrm{T}\mathbf{M}=\mathbf{I}, где \mathbf{I} – единичная матрица. Из чего следует, что \mathbf{G}=(\mathbf{M}^{-1})^\mathrm{T}. Вектор, трансформация которого происходит подобным образом (посредством транспонированной обратной матрицы преобразования), является вектором ковариантным, тогда как вектор, трансформирующийся подобно вектору касательному, является вектором контравариантным.

Однако, плоскость в однородных координатах, в отличие от нормального вектора, имеет ненулевую \mathit{w}-координату, и следует дополнительно исследовать её поведение при 4х4-преобразованиях.

Расстояние до плоскости от начала координат, после применения пространственного преобразования, с учетом особенностей преобразования нормального вектора, для лежащей в этой плоскости точки \vec{P}, через знакомое скалярное произведение:

\begin{array}{l}D{^'}= -((\mathbf{M}{^{-1}})^\mathrm{T}\vec{N})\cdot(\mathbf{M}\vec{P}+\vec{T})\\  
\qquad {}=-((\mathbf{M}^{-1})^\mathrm{T}\vec{N})^\mathrm{T}\mathbf{M}\vec{P}-((\mathbf{M}^{-1})^\mathrm{T}\vec{N})^\mathrm{T}\vec{T}\\qquad {}=-\vec{N}^\mathrm{T}\mathbf{M}^{-1}\mathbf{M}\vec{P}-\vec{N}^\mathrm{T}\mathbf{M}^{-1}\vec{T}\\qquad{}=D -\vec{N}\cdot\mathbf{M}^{-1}\vec{T},\end{array}

Мы воспользовались в данных вычислениях матрицей преобразования \mathbf{F}, дополненной к операциям поворота, масштабирования и скоса операцией сдвига:

\mathbf{F}=\left[\:\;
\begin{matrix}
\quad{} &\quad{}  &\vline &\quad{}\ \quad{} &\mathbf{M}\quad{} &\vline  &  \vec{T} \\quad{} &\quad{}  &\vline &\quad{}\\hline
 \quad{} &0\quad{} &\vline & 1
\end{matrix}\:\;\right]
=\left[\:\;
\begin{matrix}
M_{11} &M_{12} &M_{13}  &\vline \,&T_x\M_{21} &M_{22} &M_{23}  &\vline \,&T_y\M_{31} &M_{32} &M_{33}  &\vline \,&T_z\\hline
0 &0 &0 &\vline \,&1\\end{matrix}\:\;\right],

Матрица обратного преобразования к матрице \mathbf{F} ищется обычным алгоритмом обращения матриц:

\mathbf{F}^{-1}=\left[\:\;
\begin{matrix}
\quad{} &\quad{}  &\vline &\quad{}\ \quad{} &\mathbf{M}^{-1}\quad{} &\vline  &-\mathbf{M}^{-1}\vec{T} \\quad{} &\quad{}  &\vline &\quad{}\\hline
 \quad{} &0\quad{} &\vline & 1
\end{matrix}\:\;\right]
=\left[\:\;
\begin{matrix}
M_{11}^{-1} &M_{12}^{-1} &M_{13}^{-1}  &\vline \,&-\mathbf{M}^{-1}T_x\M_{21}^{-1} &M_{22}^{-1} &M_{23}^{-1}  &\vline \,&-\mathbf{M}^{-1}T_y\M_{31}^{-1} &M_{32}^{-1} &M_{33}^{-1}  &\vline \,&-\mathbf{M}^{-1}T_z\\hline
0 &0 &0 &\vline \,&1\\end{matrix}\:\;\right],

Транспонируем обратную матрицу:

{\left(\mathbf{F}^{-1}\right)^\mathrm{T}}=\left[\:\;
\begin{matrix}
\quad{} &\quad{}  &\vline &\quad{}\ \quad{} &{\left(\mathbf{M}^{-1}\right){}^\mathrm{T}}\quad{} &\vline  &0 \\quad{} &\quad{}  &\vline &\quad{}\\hline
 \quad{} &-\mathbf{M}^{-1}\vec{T}\quad{} &\vline & 1
\end{matrix}\:\;\right],

Можем видеть, что D -\vec{N}\cdot\mathbf{M}^{-1}\vec{T} из Выражения (5) есть результат умножения четвёртой строки транспонированной обратной матрицы преобразования на четырёхмерный вектор в однородной координатной записи \langle N_x, N_y, N_z, D \rangle, т.е. для плоскости \vec{C}=\langle \vec{N}, D\rangle, её образ при пространственной трансформации, описываемой 4х4 матрицей превращения \mathbf{F}, выражается:

\vec{C}{^'}={\left(\mathbf{F}^{-1}\right){}^\mathrm{T}}\vec{C}.

Для дальнейшего существенно, что плоскость подчиняется ковариантному характеру пространственного преобразования.

Перспективная проекция


Перспективное проецирование применяется, чтобы создать у наблюдателя ощущение глубины на проекционном плане, матрица перспективного преобразования должна отобразить пространство пирамиды видимости в нормализованное пространство куба видимости. Пирамида видимости обычно может быть выражена через термины top, bottom, left, right, far, near или fovy, aspect, near, far, некоторые реализации OpenGL имеют среди своих инструментов средства работы как для правосторонней так и для левой координатных систем. Отличия и порядок умножения матрицы на вектор в каждой из систем, должны быть ясны любому программисту.
frustum


Рис. 3. Усеченная пирамида видимости (frustum) в системах компьютерной графики отсекает зону видимости, для целей последующего рендеринга, с боков и вдоль осей проецирования. Пирамида видимости, в пространстве камеры вида, располагается в правосторонней системе координат так, что вершина пирамиды лежит в центре координатной системы, а направление вида из камеры противоположно оси z, ближний план находится на удалении n вдоль отрицательного направления оси z, дальний план – на удалении f вдоль отрицательного направления оси z.

В общем случае, пирамида видимости не обязана иметь форму правильной усеченной пирамиды, она может быть и асимметричной, поэтому модель с top, bottom, left, right, far, near является более подходящей для иллюстраций особенностей oblique frustum («скошенной пирамиды видимости»). «Сжатое пространство» куба видимости, замкнутое в объёме, ограниченном плоскостями x=\pm 1, y=\pm 1, z=\pm 1, для единообразия с англоязычной терминологией будем в дальнейшем называть пространством клипа.
Чтобы организовать задуманное нами отсечение части объектов в исходной пирамиде видимости, нам потребуется модифицировать применяемую в нашей модели матрицу перспективной проекции. Параметры таковой матрицы программисты OpenGL могут найти на сайте основной документации по OpenGL, программисты на Flash (AS3), вероятнее всего обратятся к классу PerspectiveMatrix3D, программисты Direct3D имеют свои источники, пишущие для андроида найдут всё необходимое в классе android.opengl.Matrix, и т.д. Не исключено, что кто-то, поняв основную идею, предпочтет расширить свой собственный класс перспективного преобразования дополнительной функциональностью.

Точка из пространства пирамиды видимости камеры вида отображается в пространство клипа канонического куба, например, следующим 4х4-матричным преобразованием (воспользуемся матрицей перспективного преобразования генерируемой glFrustum()-функцией OpenGL):

\vec{P}{^'}=\mathbf{M}_{frustum}\vec{P}= \begin{bmatrix}
\frac{2n}{r-l} &0 &\frac{r+l}{r-l} & 0\\[0.3em]
0 &\frac{2n}{t-b} &\frac{t+b}{t-b} &0 \\[0.3em]
0 & 0 &-\frac{f+n}{f-n} &-\frac{2nf}{f-n}\\[0.3em]
0 &0 &-1 & 0
\end{bmatrix}\!\!\begin{bmatrix}
P_x\P_y\P_z\1
\end{bmatrix}.

При таком преобразовании, \mathit{w}-координата преобразованной точки в однородном пространстве клипа имеет знак противоположный знаку \mathit{z}-координаты точки в пространстве камеры вида.

Особенности искажения пространства стандартной матрицей преобразования видны из Рис.4:
\mathit{z}-координата из пространства пирамиды видимости отражается в диапазон [-1, 1] NDC, причём бесконечный диапазон за дальним планом пирамиды видимости из камеры вида сжимается в конечный промежуток \left[1, \tfrac{f+n}{f-n}\right] внутри NDC; конечное расстояние от камеры до ближнего плана вдоль оси Z расширяется до бесконечного промежутка ]{-\infty}, -1] NDC; а точки вдоль оси Z, находящиеся до камеры, отражаются в диапазон \left[ \tfrac{f+n}{f-n}, \infty\right[.

Normalized Device Coordinates


Рис. 4. Отражение \mathit{z}-координаты точки из пространства камеры вида в пространство нормализованных координат устройства (NDC — normalized device coordinates).

Заменяя ближний план пирамиды видимости плоскостью отсечения, мы должны сохранить основные особенности матрицы перспективного преобразования, \mathit{z}-координата точки, лежащей на модифицированном ближнем плане, в нормализованных координатах устройства (NDC) должна остаться равной -1. Все дальнейшие наблюдения являются универсальными для любых обратимых проекционных матриц, и использование матрицы проекции из Выражения (10) служит лишь целям иллюстрации общего процесса модификации матрицы преобразования.

Если \vec{C}{^'} является одной из плоскостей, ограничивающих пространство клипа, и при этом матрица преобразования \mathbf{M} является матрицей проекции из пространства камеры в пространство клипа, то не сложно осуществить отображение этой плоскости \vec{C}{^'} в пространство камеры из пространства клипа посредством транспонированной матрицы \mathbf{M}^\mathrm{T}, что очевидно следует из Выражения (9):

\vec{C}=\left[\left(\mathbf{M}^{-1}\right){}^{-1}\right]{}^\mathrm{T}\vec{C}{^'}=\mathbf{M}^\mathrm{T}\vec{C}{^'}

Модифицирование ближнего плана пирамиды видимости


Для начала, извлечем из произвольной проекционной матрицы \mathbf{M} четырехмерные векторы, соответствующие шести плоскостям отсечения пирамиды видимости. Эрик Ленгел исходил из того, что плоскости в пространстве клипа всегда неизменны: нормаль любой плоскости параллельна одной из главных координатных осей.

На Рис.5 показаны элементы «x-z» трёхмерного среза четырехмерного однородного пространства клипа. Внутри этого среза \mathit{w}-координата любой точки равна 1, таким образом, и \mathit{w}-координата каждой плоскости равна 1, и, разумеется, одна из x-,y-, или z-координат равна ±1, что отражено в Таблице 1. Для понимания Таблицы 1 надо ещё раз внимательно посмотреть на Выражение (11): сумма некоторых двух столбцов матрицы \mathbf{M}^\mathrm{T} не что иное, как сумма соответствующих двух строк матрицы \mathbf{M}.

slice of homogeneous clip space


Рис. 5. Нормальные векторы для левой, правой, ближней и дальней плоскостей, ограничивающих однородное кубическое пространство клипа. Нормальные векторы для верхней и нижней плоскостей пространства клипа направлены от и к наблюдателю.

Табл. 1. Взаимосвязь между координатами пространства клипа и пространства усеченной пирамиды видимости камеры вида. Матрица проекции \mathbf{M} переводит пространство камеры вида в пространство клипа, и обозначение \mathbf{M}_i представляет i-ую строку матрицы \mathbf{M}.
\begin{center}
\begin{array}{rcc}
\hline
\textbf{Frustum plane} & \textbf{Clip-space} & \textbf{Camera-space} \\hline
\text{Near}\qquad{} & \langle 0, 0, 1,1\rangle &\vec{M}_4 + \vec{M}_3 \\text{Far}\qquad{} & \langle 0, 0, -1,1\rangle & \vec{M}_4 - \vec{M}_3 \\text{Left}\qquad{} & \langle 1, 0, 0,1\rangle &\vec{M}_4 + \vec{M}_1 \\text{Right}\qquad{} & \langle -1, 0, 0,1\rangle &\vec{M}_4 - \vec{M}_1 \\text{Bottom}\qquad{} & \langle 0, 1, 0,1\rangle &\vec{M}_4 + \vec{M}_2 \\text{Top}\qquad{} & \langle 0, -1, 0,1\rangle &\vec{M}_4 - \vec{M}_2 \\hline
\end{array}
\end{center}

Пусть \vec{C}=\langle C_x, C_y, C_z, C_w\rangle – некоторая плоскость, показанная ни Рис. 6, в координатном пространстве камеры вида, посредством которой мы и намереваемся ограничить нашу геометрию. Камера располагается с отрицательной стороны плоскости (со стороны противоположной направлению вектора плоскости), поэтому C_w<0. Именно этой плоскостью мы намерены заменить ближний план пирамиды видимости, поэтому, в соответствии с соотношениями из Таблицы 1, для \vec{C} должно выполняться:

\vec{C}=\vec{M}_4+\vec{M}_3.

Мы не можем модифицировать четвертую строку матрицы перспективной проекции, т.к. она используется для отражения отрицательной z-координаты в w-координату, и необходима для дальнейшей корректной работы графического конвеера. Однако, со вторым слагаемым правой части Выражения (12) мы можем поступать более свободно:

\vec{M}_3{^'}=\vec{C}-\vec{M}_4.

cut clip space

Рис. 6. Замена ближнего плана пирамиды видимости плоскостью \vec{C}.

Поскольку, согласно Таблицы 1, третья строка матрицы проекции входит в состав выражения для дальнего плана пирамиды видимости, то очевидно, что её модифицирование необходимо учесть для дальнего плана:

\begin{array}{|c|}\hline
\;\\vec{F}=\vec{M}_4-\vec{M}_3^'}\;\\[0.3em]   
\qquad {}=2\vec{M}_4-\vec{C}\;\\[1em]
\hline \end{array}\:.

И этот результат являет собой заметную проблему для перспективной проекции: поскольку \vec{M}_4=\langle0, 0, -1, 0 \rangle, то дальний план и ближний план пирамиды видимости перестают быть параллельными, в случае отличных от нуля значений для C_x и C_y. Более того, форма усеченной пирамиды приобретает вид крайне нежелательный в последующем рендеринге: рассмотрим некоторую точку \vec{P}=\langle x, y, 0, w \rangle, для которой выполняется \vec{C}\cdot\vec{P}=0, и это влечет за собой равенство нулю и \vec{F}\cdot\vec{P}, из чего мы должны заключить, что наши новые ближний и дальний планы пересекутся образом подобным показанному на Рис. 7 (а).

Проекция глубины точки, ранее достигавшая максимума на дальнем плане, и необходимая нам для процесса графической растеризации, более не представляет собой проекцию вдоль оси z, а скорее, становится значением, зависящим от положения между ближним и дальним планами. Зависимость глубины проекции от направления внутри пирамиды видимости серьезнейшим образом скажется на правильности значений буфера глубины. Однако, этот нежелательный эффект, можно снизить до приемлимого для задачи растеризации уровня, уменьшив угол между ближним и дальним планами до минимально возможного. Как и всякую плоскость, плоскость \vec{C} можно масштабировать, и это её свойство как нельзя кстати в нашем случае. Масштабирование плоскости \vec{C} скажется на ориентации дальнего плана \vec{F}, так что нам требуется лишь подобрать коэффициент масштабирования таким образом, чтобы минимизировать угол между \vec{C} и \vec{F} без ущерба для содержания сцены внутри пирамиды видимости как показано на Рис. 7 (b).
modified far plane

Рис. 7. (а) Пересечение измененного в соответствии с Выражением (14) дальнего плана \vec{F} с модифицированным ближним планом \vec{C} в «x-y»-плоскости. (b) Масштабирование ближнего плана \vec{C} параметром \alpha, введенным Выражением (17) изменяет угол между дальним и ближним планом до минимально возможного, не повреждая при этом начального вида усечения. Затененная область относится к объему пространства, не подвергнутого усечению.

Пусть \vec{C}{^'}=\left(\mathbf{M}^{-1}\right){}^\mathrm{T}\vec{C} является проекцией нового ближнего плана в пространстве клипа (\mathbf{M} – исходная матрица проекции). Угол \vec{Q}^' внутри пирамиды видимости, лежащий напротив плоскости \vec{C}, будет иметь следующие координаты:

\vec{Q}{^'}=\langle sgn(C{^'} _x), sgn(C{^'} _y), 1, 1\rangle.

Для большинства перспективных проекций, знаки компонент C{^'} _x и C{^'} _y у преобразованных плоскостей совпадут со знаками соответствующих компонент C _x и C _y, что нам позволяет воспользоваться знаками координатного разложения исходной плоскости.
Имея компоненты преобразованного угла \vec{Q}{^'}, мы уже можем вычислить компоненты оригинального угла \vec{Q}, лежащего напротив плоскости \vec{C}, как \vec{Q}=\mathbf{M}{^{-1}}\vec{Q}{^'}. В обычной пирамиде видимости, точка \vec{Q} в вершине угла, образованного пересечением двух боковых плоскостей и дальнего плана, лежащая напротив плоскости \vec{C}, является наиболее удаленной от плоскости \vec{C} точкой.

Чтобы наш дальний план содержал точку \vec{Q}, должно выполняться условие \vec{F}\cdot\vec{Q}=0, дополним Выражение (14) масштабирующим плоскость \vec{C} фактором \alpha

\vec{F}=2\vec{M}_4-\alpha\vec{C}

и найдем из условия \vec{F}\cdot\vec{Q}=0 масштабирующий фактор:

\alpha=\frac{2\vec{M}_4\cdot\vec{Q}}{\vec{C}\cdot\vec{Q}.

Замена \vec{C} на \alpha\vec{C} в Выражении (13)

\vec{M}_3{^'}=\alpha\vec{C}-\vec{M}_4

и позволит нам оптимальным образом сориентировать дальний план пирамиды видимости, как показано на Рис. 7 (b) (данная техника замещения работает корректно и для пирамиды видимости, дальний план которой удален на бесконечность,– случай бесконечной проекционной матрицы,– для этого достаточно потребовать, чтобы дальний план был параллелен одной из двух образующих противоположный плоскости \vec{C} угол граней).

Практическое использование произведенных выше наблюдений


Все ранее проделанные теоретические изыскания распространяются на любые обратимые проекционные матрицы, но, поскольку, в качестве примера уже привлекалась стандартная для OpenGL матрица в Выражении (10), то логично продолжить цепочку примеров с нею же.

Обратная матрица к ней будет выглядеть таким образом:

\mathbf{M}{^{-1}}= \begin{bmatrix}
\frac{r-l}{2n} &0  & 0 &\frac{r+l}{2n}\\[0.3em]
0 &\frac{t-b}{2n}  &0 &\frac{t+b}{2n}\\[0.3em]
0 & 0 &0 &-1\\[0.3em]
0 &0 &-\frac{f-n}{2nf} & \frac{f+n}{2nf}
\end{bmatrix}

Получим значение для третьей строки модифицированной проекционной матрицы, как предложено Выражением (18) с учетом \alpha из Выражения (17):

\vec{M}_3{^'}={\frac{2\vec{M}_4\cdot\vec{Q}}{\vec{C}\cdot\vec{Q}} \vec{C}-\vec{M}_4

Поскольку \vec{M}_4=\langle 0, 0, -1, 0\rangle, то это выражение можно записать как

\vec{M}_3{^'}={\frac{-2Q_z}{\vec{C}\cdot\vec{Q}} \vec{C}+\langle 0, 0, 1, 0\rangle

Умножив обратную матрицу из Выражения (19) на \vec{Q}{^'} из Выражения (15), мы получим \vec{Q}:

\vec{Q}=\begin{bmatrix}
sgn(C_x)\frac{r-l}{2n}+\frac{r+l}{2n}\\[0.5em]
sgn(C_x)\frac{t-b}{2n}+\frac{t+b}{2n}\\[0.5em]
-1\\[0.3em]
1/f
\end{bmatrix}

Чтобы убедиться в правильности разработанного метода модифицирования проекционной матрицы, рассмотрим частный случай расположения плоскости отсечения \vec{C} перпендикулярно оси z, т.е. параллельно обычному ближнему плану пирамиды видимости,— в координатной записи такая плоскость будет выглядеть как \vec{C}=\langle 0, 0, -1, -d \rangle, где d-некоторая положительная дистанция. Естественно ожидать, что в новой проекционной матрице для пирамиды видимости, ближний план которой удалён на расстояние d от камеры, дальний план останется в своей прежней позиции.

Скалярное произведение \vec{C}\cdot\vec{Q} для такой плоскости будет равно 1-d/f, а Выражение (21) для вычисления третьей строки модифицированной матрицы проекции приведет к

\begin{array}{l}\vec{M}_3{^'}={\frac{2}{1-d/f}}\langle 0, 0, -1, -d\rangle+\langle 0, 0, 1, 0\rangle \\[0.3em]
\qquad {}= \langle 0, 0, -\frac{f+d}{f-d}, -\frac{2fd}{f-d} \rangle\end{array}

— результату, совпавшему с ожиданиями: при d=n третья строка модифицированной матрицы совпадает с третьей строкой проекционной матрицы из Выражения (10).

Как уже предполагалось выше, следует ожидать, что процесс растеризации не будет столь же привычным, как в случае немодифицированной пирамиды видимости. Полный диапазон значений буфера глубины не будет достигаться вдоль различных направлений внутри пирамиды видимости вследствие изменения в геометрии пирамиды. Возьмем вектор произвольного направления \vec{V}=\langle V_x, V_y, V_z, 0\rangle в пространстве камеры вида, для которого V_z<0, и исследуем нормализованную z-координату точки \langle 0, 0, 1, 0\rangle + s\vec{V}, расположенной внутри пирамиды видимости:

\begin{array}{l}z(s)={\cfrac{(\mathbf{M}{^'}\langle sV_x, sV_y, sV_z, 1\rangle)_z}{(\mathbf{M}{^'}\langle sV_x, sV_y, sV_z, 1\rangle)_w}} \\[0.8em]
\qquad {}= {\cfrac{(\alpha\vec{C}-\vec{M}_4)\cdot\langle sV_x, sV_y, sV_z, 1\rangle}{\vec{M}_4\cdot\langle sV_x, sV_y, sV_z, 1\rangle}}\end{array},

где \alpha-масштабирующий фактор, введенный Выражением (17). Для \vec{M}_4=\langle 0, 0, -1, 0\rangle, Выражение (24) становится

\begin{array}{l}z(s)=\cfrac{\alpha sC_xV_x+\alpha sC_yV_y+\alpha sC_zV_z+sV_z+\alpha C_w}{-sV_z} \\[0.8em]
\qquad {}=\cfrac{\alpha s (\vec{C}\cdot \vec{V}) +sV_z+\alpha C_w}{-sV_z}\end{array}.

Мы полагаем, что скалярное произведение \vec{C}\cdot \vec{V} \geq 0, поскольку иначе точка \langle 0, 0, 1, 0\rangle + s\vec{V} лежала бы вне пирамиды видимости. Рассмотрим ситуацию, когда s стремится к бесконечности:

\lim_{s \to \infty} z(s)=-\cfrac{\alpha(\vec{C}\cdot \vec{V})+V_z}{V_z},

полученное выражение указывает максимально достижимое значение нормализованной z-координаты в направлении \vec{V}.
Исследуем направление \vec{V}=\langle 0, 0, -1, 0\rangle вдоль прямого взгляда из позиции камеры: предельное значение, указанное Выражением (26), меньше единицы, если выполняется условие \alpha C_z >-2. В этом случае, z-координата дальнего плана \vec{F}, заданного Выражением (16), меньше нуля, и дальний план не является плоскостью, ограничивающей объем пирамиды видимости. Поскольку дальний план может оказаться не достижимым вдоль направления \vec{V}, диапазон нормализованных значений для буфера глубины может оказаться существенно уже, чем в случае обычной пирамиды видимости.

Хорошей практикой для программиста будет, перед тем, как утвердить для дальнейшей работы выбранную пространственную модель, исследовать поведение нормализованной координаты внутри модифицированной (скошенной | oblique frustum) пирамиды видимости. Своевременно обнаружив проблемные места, он может поправить или положение камеры, или изменить угол наклона секущей плоскости таким образом, чтобы упростить работу буфера глубины, по возможности приблизив её к нормальному режиму. Затраты на такое действие не будут особенно значительными, но результат послужит спокойствию перфекциониста.
Продолжая эксплуатировать стандартную матрицу проекции из Выражения (10), легко перейти к очередному примеру её использования для исследования значений нормализованной z-координаты внутри модифицированной пирамиды видимости:

допустим, что плоскость, отсекающая неугодную нам геометрию, и которой мы замещаем ближний план пирамиды видимости, в направляющих косинусах представлена как \vec{C}=\langle C_x, C_y, -C_z, -d \rangle, и, в нашем частном случае, C_x, C_y, C_z имеют положительные значения (плоскость лежит напротив правого верхнего угла пирамиды), при этом C_z-угол между отрицательным направлением оси z и нормальным вектором нашей плоскости. Рассмотрим изменение нормализованной z-координаты вдоль отрицательного направления оси z в зависимости от угла между нормальным вектором плоскости ближнего плана и отрицательным направлением оси z, и расстоянием от камеры до ближнего плана.

Скалярное произведение \vec{C}\cdot\vec{Q} для этого случая, с учетом Выражения (22) даст следующий результат:

\vec{C}\cdot\vec{Q}=\cfrac{rfC_x+tfC_y-n(d-fC_z)}{nf},

и третья строка преобразованной матрицы проекции приобретет вид

\begin{array}{l}\vec{M}_3{^'}={\cfrac{2nf\langle C_x, C_y, -C_z, -d\rangle}{rfC_x+tfC_y-n(d-fC_z)}+\langle 0, 0, 1, 0\rangle}\end{array}.

Рассмотрим поведение нормализованной координаты z в направлении фронтального вида из камеры для точек \vec{P}=\langle 0, 0, P_z, 1 \rangle, из диапазона значений P_z \in [-n, -f]: нормализованная z-координата для этого случая станет

z={\frac{P_z^'}{P_w^'}}=-\cfrac{(rfC_x+tfC_y-n(d+fC_z))P_z-2nfd}{(rfC_x+tfC_y-n(d-fC_z))P_z} \; .

Последнее Выражение вполне подходит для целей численного исследования. Пример такого исследования можно видеть на Рис. 8. Диапазон нормализованных значений, предназначенных для буфера глубины, сильно сужается с ростом угла между нормалью плоскости и отрицательным направлением оси z, также значительно ухудшить точность работы буфера глубины может перемещение ближнего плана по направлению от камеры к дальнему плану (известно, что слишком близкое размещение к камере ближнего плана также неблагоприятно сказывается на значениях нормализованных координат).
modified far plane

Рис. 8. Сужение диапазона нормализованной z-координаты в направлении проекции \vec{V}=\langle 0, 0, -1, 0 \rangle, в зависимости от угла между нормаль-вектором ближней (секущей) плоскости и отрицательным направлением оси z, и расстоянием от камеры до ближней (секущей) плоскости. Значения, близкие к 1, соответствуют ситуации, когда исследуемая пространственная точка располагается вблизи модифицированного дальнего плана, при этом ближний план достаточно удален от дальнего плана и его нормаль-вектор незначительно отклонен от отрицательного направления оси z. С ростом угла и перемещением ближнего плана в направлении от камеры, диапазон нормированных значений z-координаты сужается до значений малопригодных для работы большинства буферов глубины.

Заключение


Программисту в процессе разработки приложения часто приходится искать компромисс между быстродействием и реалистичностью рендеринга. Техника, изложенная в настоящей статье, позволяет не только достичь максимального быстродействия на самом широком спектре устройств, но и помогает определить ситуацию, в которой желательно отредактировать сцену, для наиболее благоприятного ее отображения.

Совмещение процессов модификации пирамиды видимости и тестирования работы буфера глубины для модифицированной пирамиды (или учет произведенных выше наблюдений) — залог высокого качества конечного результата непростого труда программиста.


Литература


[1] Eric Lengyel, Oblique View Frustum Depth Projection and Clipping. Journal of Game Development, Vol. 1, No. 2 (March 2005), pp. 5–16.

[2] Eric Lengyel, Mathematics for 3D Game Programming and Computer Graphics. Charles River Media, 2002, p. 103.

Комментарии (6)


  1. PapaBubaDiop
    26.09.2017 19:23

    По мне, если не экономить память, куда быстрее строить отраженные объекты в том же пространстве с отраженным источником освещения. И все проблемы с отсечением исчезнут.


  1. nailer Автор
    26.09.2017 20:03

    Возможно, я не вполне понял Ваше замечание, но техника отсечения как раз и применяется к пространству камеры отражения (?). Как раз в ней и строятся «отраженные объекты с отраженным источником света». Конечная растеризация осуществляется по совокупности фрагментов от матриц отражения и основной. Для каждого отражения — своя матрица (если их более одного). На рисунке, предваряющем статью, два отражения, одно из них — во фронтально стоящем зеркале, другое — в поверхности стола, для сохранения реалистичности «резы» неизбежны.


    1. PapaBubaDiop
      26.09.2017 23:55

      Нет, я говорю о варианте без камеры отражения. Объекты отражаются в реальном пространстве относительно плоскости отражения и строятся в общем z-буффере. Но это конечно работает для несложных сцен — типа 4 кубиков)


      1. nailer Автор
        27.09.2017 07:33

        Мне кажется такая техника довольно трудоемкой (если я правильно Вас понял, то предлагается продублировать объекты в сцене в соответствующем отражению координатном представлении), хотя, вероятно, применимой в некоторых ситуациях, но в случае, например, динамических сцен, придется геометрию каждого входящего в сцену объекта (псевдоотраженного) править (если этот объект должен лишь некоторой своей частью быть видимым в сцене), искажая его геометрию подобно «отсечению» (а самая эта «геометрия» может быть довольно сложной). Ничего нереального, конечно, в этом нет, но затраты могут быть много выше, чем «колдовство» с плоскостями и матрицами.


        1. Nick_mentat
          28.09.2017 12:51

          Движок компьютерной игры может быть оптимизирован таким способом, чтобы заранее просчитать порядок прорисовки объектов и составить для них дерево. В таком случае расчёт видимости/невидимости полигонов объектов из отражённой сцены на лету оказывается абсолютно невозможным. С другой стороны этот порядок очень просто наследуется при отражении камеры.


  1. nailer Автор
    28.09.2017 21:33

    Вообще, считаю, что такие основополагающий вещи, как Oblique Frustum должны быть известны, понятны (и, по моему мнению, интересны) любому программисту, несмотря на то, владеет ли он замечательным коммерческим движком, в котором реализовано все мыслимое и предвосхищающее его фантазии, или обладает ограниченным инструментарием для воплощения своих планов. Для более выразительной иллюстрации применения отсекающих плоскостей, прилагаю рисунок:



    Специально убрал первый кубик, оставив только его отражения в столе и фронтально стоящем зеркале. Геометрия в обоих случаях обрезается способом, описанным в статье.