Фантазии о Вселенной и мой личный сайт
Проецирование 3D на 2D

Проецирование 3D на 2D

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

В чем суть проецирования? Оно немного отличается от того, которое можно назвать физическим, оптическим, но суть его остается та же. Посмотрим, сначала, как это делает глаз.


Рисунок 1. Проекции

Смотря на рисунок, можно понять всё, если захотеть. Но я поясню. Собственно, мы видим, что изображение проходит через линзу (глаз), оно попадает в перевернутом виде на сетчатку (изображено слева). Расстояние, на котором изображение становится резким, называется фокусом. То есть, все лучи из одной точки фокусируются.

Что-то сразу же хочется к формулам перейти. Итак, мы видим, что есть отрезок (CF), который является исходным, и есть отрезок GE, который является проецируемым. Как видно, изображение, которое попадает на сетчатку, очень мелкое, но сохраняет пропорции. Обращу внимание на "-focus" и "+focus", они равняются расстояниями от линзы до сетчатки. "-focus" = AG, "+focus" = AB. Я сделал их равными, но это неважно.

Давайте немного приглядимся. Что такое проекция? Это когда какой-то объект, например 3-х мерный, проецируется на 2-х мерное пространство. Так оно и происходит в глазу. Итак, у нас есть треугольники ABD и ACF. Они имеют прямой угол в 90 градусов. Это прямоугольные треугольники. Теперь второе. Один треугольник вложен в другой треугольник, т.е. эти треугольники еще и подобные. Это значит, что они сохраняют пропорции друг друга, один треугольник - это копия другого треугольника в другом масштабе. Что это значит? Это отличная возможность опять применить математику к ним:

$$ \frac{AC}{AB} = \frac{FC}{BD} = \frac{AG}{AC} = \frac{EG}{CF} $$

Расписал я тут, но суть ясна. Все пропорции равны между собой.

Теперь давайте представим, что CF = y, AC = z, а AB - это какое-то жестко заданное значение, то есть AB = focus. Мы его однажды взяли за какое-то определенное число, и менять его не будем. Будем считать, что фокусное расстояние это расстояние от глаза до некой плоскости, типа экрана, или кинотеатра, которое мы не меняем.

FC = y, это высота нашего объекта в натуральную величину. Например, высота дерева. Расстояние AC (или z), это расстояние дерева от глаза в трехмерном пространстве. Нам надо получить BD (точку проекции, назовем ее y').

$$ \frac{AC}{AB} = \frac{CF}{BD} $$

Что то же самое, если подставить другие буквы:

$$ \frac{z}{focus} = \frac{y}{y'} $$

Как отсюда получить y'? Да просто:

$$ y' = \frac{y*focus}{z} $$

Ровно аналогично это можно сделать для x', совершенно так же:

$$ x' = \frac{x*focus}{z} $$

Вот и все. Вот с помощью этих формул и выходит проекция на экран монитора. Но я еще вот что делаю, я добавляю к x' и y' некие значения, а точнее, половину от длины экрана и высоты. Почему? Очень просто. Если мы смотрим на объект прямо, то его проекция будет находиться в точке (0,0), это значит, что в левом верхнем углу экрана будет центр объекта. А что если спроецируется левая часть объекта? Она будет выходить за левые рамки экрана. Поэтому я добавляю к x' и y' половину от размера экрана. Допустим, если у нас экран будет 640 x 480, то, чтобы получился центр, надо к x' добавить 320, а к y' 240. Но делаю не так. Дело в том, что координатная сетка идет снизу вверх. Получается, если дерево имеет высоту 1, то оно должно расти вверх, а вверх в экране - это в сторону уменьшения Y.

Это как? Вот у нас, если взять Y=0, она будет наверху, а Y=480 будет внизу. Если же дерево имеет высоту Y=100, например, то y' тоже будет увеличиваться, если дерево растет, а увеличение y' будет рисовать точку внизу экрана. Поэтому я вычитаю из 240, а не добавляю к нему для Y.

$$ x' = 320 + \frac{x*focus}{z} \\ y' = 240 - \frac{y*focus}{z} $$

Здесь 320 и 240 взяты для примера.

Как итог. Эта формула используется для любых вычислений проекции в 3Д. Она очень важная. Это вычисляется именно перспективная проекция. Когда я ее отыскал, я был нереально счастлив в свое время. Она простая и такая понятная.