По сути, у нас есть три важные системы координат в этой задаче:
У нас есть обычная трехмерная мировая система координат, которую можно определить произвольно. У нас есть 2D система координат для плоскости. Источник этой системы координат находится в центре плоскости (обратите внимание, что для этой цели я использую термин плоскость как синоним прямоугольник ), а координаты находятся в диапазоне от -1 до +1. И наконец, у нас есть 2D координата для изображения. На самом деле у нас есть две для изображения: система координат без знака (как показано на рисунке) с началом координат внизу слева и координатами в диапазоне от 0 до 1, и система со знаком с координатами в диапазоне от -1 до 1.
Мы знаем четыре угла нашей плоскости в мировом пространстве и матрицу 3x4 вида / проекции P
, которая позволяет нам проецировать любую точку в мировом пространстве на пространство изображения, используя однородные координаты:
p_image,signed = P * p_world
Если ваша матрица проекции имеет размер 4x4, просто отбросьте третью строку (последнюю, но 1), поскольку нас не интересует глубина пространства изображения.
На самом деле мы не заботимся о мировом пространстве, поскольку это несколько произвольно. Учитывая 2D точку в плоском пространстве, мы можем преобразовать ее в мировое пространство, используя:
p_world = 1/4 (p0 + p1 + p2 + p3) + u * 1/2 * (p1 - p0) + v * 1/2 * (p3 - p0)
Первая часть - это начало плоскости, а точечные различия во втором и третьем членах - это оси координат. Мы можем представить это в матричной форме как
/ x \ / p1_x - p0_x p2_x - p0_x 1/4 (p0_x + p1_x + p2_x + p3_x) \ / u \
| y | = | p1_y - p0_y p2_x - p0_x 1/4 (p0_y + p1_y + p2_y + p3_y) | * | v |
| z | | p1_z - p0_z p2_x - p0_x 1/4 (p0_z + p1_z + p2_z + p3_z) | \ 1 /
\ 1 / \ 0 0 1 /
Давайте назовем эту матрицу M
.
Теперь мы можем перейти непосредственно из плоского пространства в пространство изображения с помощью:
p_image,signed = P * M * p_plane
Матрица P * M
теперь является матрицей 3х3. Это гомография между вашей земной плоскостью и плоскостью изображения.
Итак, что мы можем с этим сделать? Мы можем использовать его, чтобы нарисовать изображение в плоском пространстве. Итак, вот что мы собираемся сделать:
Мы создадим цель рендеринга, которую мы заполним одним вызовом отрисовки. Эта цель рендеринга будет содержать текстуру нашей плоскости. Чтобы нарисовать это, мы:
- Загрузка изображения камеры в графический процессор в виде текстуры
- Привязать цель рендеринга
- Нарисуйте полноэкранный четырехугольник с углами
(-1, -1), (1, -1), (1, 1), (-1, 1)
- В вершинном шейдере вычислить координаты текстуры в пространстве изображения из плоского пространства
- В пиксельном шейдере сэмплируйте изображение с камеры по интерполированным координатам текстуры
Интересная часть - номер 4. Мы почти знаем, что нам нужно делать. Мы уже знаем, как перейти в подписанное пространство изображений. Теперь нам просто нужно перейти в пространство без знака. А это простой сдвиг и масштаб:
/ 1/2 0 1/2 \
p_image,unsigned = | 0 1/2 1/2 | * p_image,signed
\ 0 0 1 /
Если мы назовем эту матрицу S
, мы можем затем вычислить S * P * M
, чтобы получить одну матрицу 3x3 T
. Эту матрицу можно использовать в вершинном шейдере для вычисления координат текстуры из точек плоскости, которые вы передаете:
texCoords = p_image,unsigned = T * p_plane
Важно, чтобы вы передали весь трехмерный вектор фрагментному шейдеру и делили перспективу только в пиксельном шейдере, чтобы получить правильную перспективу.