InfoCity
InfoCity - виртуальный город компьютерной документации
Реклама на сайте







Размещение сквозной ссылки

 

3D изнутри


Дмитрий Сытник, Мой Компьютер


Сейчас трудно найти человека который хоть раз в жизни не играл бы в трехмерные игры. Более того, я уверен, что для многих это любимое занятие. Но задумывался ли кто-то, что стоит за красивой картинкой на экране? Как получается трехмерное изображение в игре? В этой статье я хотел бы приоткрыть завесу тайны и рассказать о том, как устроены современные 3D-игры. И сделать это я бы хотел на примере популярной игры Quake 3 Arena.

Как известно, вся трехмерная графика в игрушке состоит из полигонов. Полигон в игрушках - это выпуклый многоугольник. Я надеюсь, вы хорошо себе представляете, как выглядит многоугольник на плоскости экрана? Координата Х, координата Y, центр координат - верхний левый угол... В трехмерном изображении все то же, только центр координат находится в центре экрана и добавляется еще одна - Z-координата, которая уходит вглубь экрана (имеет положительный знак). Вот из таких-то полигонов и состоит вся графика в игрушке.
Любой выпуклый полигон, в свою очередь, можно разбить на треугольники. Например, ромб можно разбить на 2 или 4 треугольника. Все это происходит в процессе построения изображения. Зачем это нужно? Ответ тривиален - компьютеру значительно проще изобразить на экране треугольник, чем сложный выпуклый полигон, состоящий из n-ного количества граней. Так что треугольники - это кирпичики трехмерной графики (точнее, полигонной графики - ведь есть и другие разновидности).
Теперь понятно, из чего состоят уровни. Все это - десятки тысяч полигонов, которые потом разбиваются на еще меньшие элементы - треугольники. Чем больше полигонов, тем более гладким и детализированным становится изображение, но тем больше игра "тормозит", соответственно, больше требует памяти - все имеет свою цену. Даже кривые, и те состоят из полигонов. Может быть, помимо стилизации изображений, есть и какие-то иные методы экономии полигонов. Стилизация стилизацией, а ведь хочется реалистичности, однако...

Невидимки


Тут становится вопрос о HSR - Hidden Surface Removal (удаление невидимых поверхностей). В Quake это делается с помощью PVS - Potential Visibility Set (список потенциальной видимости). Попробуем объяснить фигурально. Например, если вы стоите дома в кухне, то вы можете видеть, положим, только коридор и ванную. Спальню, большую комнату и балкон вы никак видеть не можете. И наоборот, стоя на балконе, вы никак не можете видеть ни кухню, ни ванную. Так зачем тратить время на прорисовку и расчет этих комнат, если они не попадают в пределы вашей видимости? Список потенциально видимых комнат - это и есть PVS, список потенциальной видимости.
Игра тоже состоит из так называемых комнат - кластеров. Кластер - это, грубо говоря, кусок уровня. Он состоит из полигонов. Пресловутый PVS и есть список видимых кластеров, составленный для каждого кластера в отдельности. Составление этого списка - дело различных утилит, использующихся на этапе проектирования уровня. Изображение строится так: сначала определяется кластер, в котором находится игрок. Далее мы берем полигоны из потенциально видимых кластеров и обрабатываем их. Таким образом, мы работаем только с нужными нам полигонами.
На следующем этапе мы трансформируем эти полигоны. Зачем нужна трансформация и что это такое? В игрушке мы ведь не стоим на месте, а движемся, занимая определенные координаты в игровом пространстве. Все полигоны заданы статично, мы же их должны по мере необходимости трансформировать относительно движения игрока. То есть, в действительности происходит так: не игрок движется относительно полигонов и уровня, а уровень движется и вращается относительно игрока. Как осуществляются эти трансформации?
Очень просто. Сначала мы должны прибавить (или вычесть - все равно, просто поменяется направление движения) к каждой координате координаты игрока. Таким образом, игрок всегда будет находиться в центре координат. Затем осуществляется поворот - по формулам, известным любому первокурснику. В результате, мы получим полигоны, трансформированные относительно игрока. Отлично! Уже полдела сделано. Остается только определить, какие полигоны попадают в наше поле зрения.
Например, став в кухне лицом к стене, мы не увидим ни коридора, ни ванны. Вот почему одного списка потенциальной видимости мало. Игра отсекает все полигоны, которые находятся за спиной у игрока. Это осуществляется простой проверкой - если все координаты вершин полигона Z меньше нуля, значит, мы не увидим этот полигон. Но и это еще не все. Оказывается, мы также можем уменьшить количество изображаемых полигонов. Тут стоит заметить, что все вершины полигонов уровня заданы в одном направлении - или по часовой стрелке, или против (см. рисунок).
Так вот, вычислив нормаль трансформированного полигона, мы можем узнать, куда он, грубо говоря, "смотрит". Ведь нормали - это направления. Если нормаль положительна - значит, полигон смотрит на нас, если отрицательна, то полигон обращен "спиной" к нам. Таким образом, остаются только те полигоны, которые могут быть видимы - они-то и выводятся на экран. Но и тут возникает проблема. Мы знаем, какие полигоны мы видим. Но как их вывести на экран, ведь дальние полигоны могут перекрыть ближние, и получится исковерканное изображение?

Перспектива


Компьютеру все равно, какие полигоны находятся ближе, а какие - дальше. Для этого используется один из алгоритмов прорисовки трехмерных поверхностей. Например, можно отсортировать полигоны по их средним Z-координатам и вывести в этой последовательности на экран. Но этот способ не во всех случаях может дать корректное изображение. Есть еще один способ, в настоящее время имеющий широкое применение на аппаратном уровне. Зная координаты каждой вершины в пространстве, их можно попросту интерполировать (об интерполяции ниже) и узнать координаты каждой точки полигона в трехмерном пространстве. Нас пока интересует только Z-координата, ее мы и интерполируем.
Дополнительно к экранному буферу используется еще один, таких же размеров, в котором находятся очень большие числа. Узнав для данной интерполированной точки полигона Z-координату, мы смотрим в этот внеэкранный буфер. Если находящееся там число больше, чем наша Z-координата, то мы записываем ее туда, а на экран выводим соответствующий пиксель текстуры полигона. Если какой-то полигон и его конкретная точка в данном месте окажется ближе, то эта точка и в буфере, и на экране заменяется. Выглядит достаточно громоздко, но и OpenGL, и Glide, и Direct3D умеют все это делать на аппаратном уровне, благодаря чему получается вполне приемлемая скорость. Раньше разработчикам игр оставалось только нарисовать на экране треугольники, наложив на них конкретные текстуры. Но сейчас, после выхода Quake III, технология усложнилась.

Текстура


Теперь на полигон может налагаться или обычная текстура (для тех, кто не знает, текстура - это двухмерное изображение, которое потом отображается на полигоне), или shader. Shader - это скриптовый файл, в котором указана последовательность "косметических" преобразований данного полигона: смешение нескольких текстур, анимация текстуры, прозрачность и т. п. Все это задается в текстовом формате. Как же происходит процесс наложения текстур?
Скажем так: полигон - плоскость, расположенная в трехмерном пространстве. Стало быть, каждой точке полигона, помимо абсолютного значения в пространственной системе координат, присущи относительные координаты двумерной системы - к ним-то и привязывается текстура. То есть, такой-то точке полигона соответствует определенный пиксель текстуры (10,10). Это осуществляется по простым формулам:
1. SREEN_X=X_RES/2+VDIST*(X/Z);
2. SREEN_Y=Y_RES/2+VDIST*(Y/Z);
где SCREEN_X, SCREEN_Y - координаты точки на экране; X, Y, Z - координаты трехмерной точки; X_RES, Y_RES - разрешение экрана (например, 640x480); VDIST - специальная величина, масштабирующая изображение, или расстояние от камеры до начала координат по Z. Полученные двумерные координаты текстуры и точки интерполируются между собой, и на экране получается трехмерное изображение. Что такое интерполяция?
Интерполяция - это изменение числа от a до b за n шагов. Предположим, нам надо интерполировать 1 до 5 в 9 шагов. Мы получаем следующий ряд: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5. Таким же образом, зная координаты вершин, мы можем, интерполировав их, получить промежуточные координаты для каждой точки. Если кому-то интересно, то формула интерполяции следующая:
3. rez = start+step*(end-start)/num_steps;
где rez - результат интерполяции; end, start - первое и последнее число ряда; num_steps - количество шагов; step - текущий шаг, находящийся в интервале от 0 до num_steps.
При изображении полигона может применятся билинейная фильтрация -стандартный по нынешним временам эффект размытия пикселей при увеличении полигонов. Раньше при приближении к стенам пиксели увеличивались, и текстура получалась квадратной - получаемые в результате интерполяции нецелые координаты полигона "усреднялись" пикселями текстур. При билинейной фильтрации используется следующий трюк. При получении каких-то нецелых двумерных координат точки мы находим ближайшие целые пиксели текстуры и интерполируем их цвет, используя в качестве текущего шага интерполяции нецелое значение, полученное в текущей точке. Происходит нечто наподобие градиентной растяжки - для каждой точки мы получаем точное промежуточное значение, а не округленное целое.


Реклама на InfoCity

Яндекс цитирования



Финансы: форекс для тебя








1999-2009 © InfoCity.kiev.ua