скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Основы 3D математики - Работа с камерой



Проецирование

Например, у нас задан в пространстве треугольник ABC, у каждой вершины, ес-сно, заданы координаты x,y,z. Как все это безобразие спроецировать на экранную плоскость? Я буду описывать в данной статье только перспективное проецирование.

Существуют стандартные фомулы проецирования:


x` = x*FOV/z + xRes/2
y` = y*FOV/z + yRes/2

  • x`, y` - координаты искомой точки на плоскости;
  • x,y,z - координаты исходной точки в пространстве;
  • xRes,yRes - графическое разрешение экрана;
  • FOV - угол обзора камеры.

камера находится в (0;0;0), и направлена по оси z, такая камера называется "стандартной".

Произвольная камера

Вас устраивает камера, всегда расположенная в начале координат, и повернутая в одном направлении? :) нет конечно :) Камера, расположенная произвольно в пространстве и повернутая под произвольным углом называется "произвольной".

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

Z-Отсечение

Если Вы уже попробовали сделать вышенаписанное, то наверняка столкнулись с проблемой - если точка-вершина расположена за камерой, т.е. ее z-координата при приведении к стандартной камере < 0, она неправильно проецируется, а если z-координата этой точки = 0 - деление на 0.. если взглянуть на формулы проецирования, можно увидеть, почему так происходит..

Если Вам требуется спроецировать только одну-лишь точку, не связанную ни с чем - все просто - Вы можете при z <= 0 просто отказаться от ее проецирования. Но если это - вершина треугольника? Ее отбросить никак нельзя. Решение этой проблемы - в отсечении полигона по оси Z.

Вот алгоритм такого отсечения(берем, к примеру, треугольник, как самый простой полигон):

  1. Проверяем z-координаты всех вершин, если есть точки, у которых z-координаты <=0 - проводим отсечение (если у всех вершин полигона z-координата <= 0 - вообще пропускаем этот полигон).
  2. Последовательно проверяем каждую вершину (по или против часовой стрелки). Если сторона, которую образует эта вершина и след. по порядку, пересекается с осью z - находим координаты точки пересечения стороны с осью, они будут координатами одной из вершин искомого полигона; eсли следующая точка после рассматриваемой лежит в положительной полуплоскости z (или, что правильнее, xy)- тогда сохраняем координаты след. точки после просматриваемой в искомые; если сторона не пересекает ось z, лежит в отрицательной полуплоскости - пропускаем ее.

Немного запутанное объяснение, но - вернемся к нашему примеру с треугольником ABC, отсечем его по оси z.

Начнем с точки A, след. точкой будет точка B. Сторона AB лежит в отрицательной полуплоскости, пропускаем. Дальше - точка B, следующая - C. Сторона BC пересекается с осью z, т.к., просто-напросто, у точки B координата z < 0, а у точки C координата z > 0; находим точку пересечения стороны с осью z. добавляем эту точку в список искомых; так как точка C лежит в положительной полуплоскости - добавляем ее в список искомых. Дальше рассматриваем точку C, следующая точка - A. Сторона CA, опять же, пересекает ось z, находим точку пересечения этой стороны с осью z... опять же добавляем ее в список искомых. Все, мы "обошли" все вершины полигона, найденые вершины B'CA' как раз и образуют отсеченный по оси z полигон.

Небольшое примечание - отсекать надо не по оси z, т.е. координата z линии отсечения = 0, а по линии, находящейся очень близко к оси z, и лежащей в положительной полуплоскости (например, z=0,0001) - чтобы избежать деления на 0 при проецировании.

2D-Отсечение

Мы уже можем управлять камерой, корректно проецировать полигоны на экранную плоскость.. не хватает одного в работе с камерой - 2D-отсечения. Экранные координаты ограничены разрешением экрана, например, 800x600. И, к примеру, спроецированный полигон получился такой (ABC):

Мы воспользуемся аналогичным описанному выше алгоритмом, только сейчас мы будем отсекать прямые не по плоскости, а по прямым. Фактически, мы будем отсекать полигон последовательно по левой, нижней, правой, верхней границам экрана точно также, как и отсекали полигон по плоскости z - единственное, искать пересечение для точки будем уже не для 3D, а для 2D случая.

Для данного полигона:

  1. отсекаем по левой границе. полигон ABC.
  2. отсекаем по нижней границе. полигон AA`B`C
  3. отсекаем по правой границе. полигон AA`B`B``C`
  4. отсекаем по верхней границе. полигон AA`B`B``C`.

существуют и другие способы отсечения, но этот - один из самых известных. этот алгоритм носит название алгоритм Сазерленда-Ходжмана(Sutherland-Hodgman algorithm).

В принципе, вот и все о работе с камерой.






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook