Игры

Анатомия игровых движков

⇣ Содержание

С момента появления Doom прошло уже много времени. Но эта игра не просто была хитом, она реализовала новую модель игрового программирования, базирующуюся на игровом «движке» (engine). Подобный модульный и расширяемый дизайн позволил игрокам и программистам видоизменять игровое ядро - создавать новые игры с новыми моделями, сценарием, звуками, или изменять существующий материал. Среди многочисленных новых игр, созданных на базе существующих движков, можно отметить CounterStrike, Team Fortress, TacOps, Strike Force и даже Quake Soccer. Большинство из них построено на движке Quake от iD.

TacOps и Strike Force используют движок Unreal Tournament. Фактически, термин «движок» уже устоялся в игровой среде, но где же кончается движок и начинается игра? И что на самом деле происходит за кулисами игры, как на экран выводятся все эти пиксели, как проигрываются звуки, как думают монстры и почему в игре случаются определенные события? Если вас интересует любой из поставленных вопросов, и вы желаете узнать больше о играх, то вы пришли по адресу. Мы постараемся дать глубокий и всесторонний экскурс в игровые движки, фокусируясь на движках Quake.

Введение

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

Если вы когда-либо обращали внимание на структуру игры Quake, то в ней движком является quake.exe, а игровые части - это QAGame.dll и CGame.dll. Впрочем, сейчас вам это может ни о чем не говорить. Что ж, все еще впереди.

Визуализатор (renderer)

Итак, начнем наш разговор об игровых движках с визуализатора, причем говорить мы будем с точки зрения разработчика. Фактически, во всех дальнейших частях «Анатомии...» мы будем рассматривать движок именно с такой точки зрения.

Итак, что такое визуализатор и почему он столь важен? Дело в том, что без него вы ничего на экране не увидите. Он визуализирует сцену для игрока, чтобы он смог принимать определенные решения на основе отображаемой на экране информации. Визуализатор, в общем-то, первая вещь, которую вам нужно создать при построении игрового движка. Ведь если вы ничего не видите, то как вы узнаете, что ваш код работает? На визуализатор обычно уходит более 50% ресурсов процессора, и именно за визуализатор игровых разработчиков чаще всего и критикуют. Если вы напишите его с ошибками, то через десять дней вся индустрия будет смеяться над вашими программистскими талантами, над вашей игрой и над вашей компанией. На визуализатор также очень часто смотрят продавцы, и именно его часто принимают во внимание при оценке той или иной игры. После этого вас, наверное, не сильно вдохновляет идея создания визуализатора, но без хорошего визуализатора ваша игра никогда не попадет в Top 10.

Визуализатор в наши дни должен использовать 3D ускоритель, API, трехмерные вычисления. Так что вам нужно обязательно разобраться, как же работает 3D «железо». Для приставок сейчас требуются аналогичные знания, но с приставками, по крайней мере, вам не требуется достичь постоянно меняющейся цели. Железо приставки не меняется, в отличие от ПК, на протяжении всего времени ее жизни.

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

Создание 3D мира

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

3D объекты хранятся в виде точек трехмерного мира (их еще называют вершинами), причем они связаны друг с другом определенным образом, так что компьютер знает, между какими точками проводить линии или какие точки образуют поверхность. Представьте себе коробку. Она имеет восемь точек в углах. При этом коробка состоит из шести поверхностей, каждая из них образует сторону коробки. Только что мы описали объект в трехмерном мире. Как видим, ничего трудного здесь нет. Если же мы будем рассматривать более сложные вещи, к примеру, уровень в Quake, то там используются тысячи вершин (даже ближе к сотням тысяч), и тысячи полигональных поверхностей. Выше вы видите фигуру монстра, выполненную в виде проволочного каркаса. Она очень близка к описанию коробки, которое мы дали выше. Отличие здесь так же заключается в числе вершин и количестве маленьких полигонов, из которых состоит монстр.

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

В хорошем движке всегда возможна полная замена визуализатора на новый, при этом не потребуется залезать в игровой код. Многие кросс-платформенные движки типа Unreal, и многие доморощенные приставочные игровые движки предоставляют такую возможность. К примеру, в версии игры под GameCube можно легко заменить визуализатор.

Но давайте вернемся к представлению объектов. Дело в том, что в компьютере существуют и другие способы представления точек в пространстве помимо использования координатной системы. Вы можете задать их математически, используя функцию для описания прямых или кривых линий. Затем будут вычислены полигоны, которые практически все 3D карты используют в качестве окончательных единиц (примитивов) рендеринга. Примитив - это минимальная единица рендеринга, которую вы можете использовать на графической карте, и практически все железо сейчас понимает под примитивом полигон с тремя вершинами, а проще говоря - треугольник. Новые карты ATi и nVidia позволяют вам производить математический рендеринг (с помощью поверхностей высокого порядка), но такая функция не распространена среди других карт, поэтому ее еще рано использовать в качестве базовой стратегии рендеринга.

Конечно, математический рендеринг иногда слишком дорогостоящ с точки зрения вычислений, но он интересен в качестве основы для новых и экспериментальных технологий, типа создания рельефа или смягчения краев объектов. Мы более подробно опишем поверхности высокого порядка в разделе про патчи.

Отбрасывание невидимых вершин и полигонов (culling)

Давайте представим себе мир, описанный сотнями тысяч вершин/полигонов. Скажем, вы используете вид от первого лица, которое смотрит сбоку на наш трехмерный мир. В поле зрения человека находится множество полигонов нашего мира, хотя огромное их количество человек просто не видит, поскольку другие объекты, типа стены, их закрывают. Даже лучшие игровые программисты не могут обработать 300 000 треугольников на современных 3D картах при сохранении 60 fps. Карты просто не обладают такой мощью, поэтому нам нужно приложить некоторые усилия для отбрасывания полигонов, которые человек не видит, перед передачей сцены карте. Этот процесс называется отбрасыванием невидимых вершин и полигонов (culling).

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

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

Это число обычно высчитывается при условии, что все полигоны находятся на экране, они используют одну и ту же текстуру, они одинакового размера, при этом приложение ничем не занимается, кроме как отсылкой полигонов на карту. Однако в реальных ситуациях, как вы можете догадаться, приложение параллельно занимается множеством других вещей - осуществляет 3D трансформацию полигонов, освещение полигонов, передает дополнительные текстуры в память видеокарты и т.д. При этом на карту требуется отправить не только текстуры, но и данные для каждого полигона. Некоторые новые карты позволяют вам хранить данные о геометрии модели и мира внутри памяти самой карты, но такой подход слишком дорог с точки зрения занимаемого пространства, которое обычно отводится под текстуры. К тому же в данном случае нужно удостовериться, что посланные вершины модели будут использоваться в каждом кадре, иначе вы просто впустую потратите память на карте. Но мы немного отвлеклись. Главное, что вам здесь следует понять - то, что вы читаете на коробке с вашей новой видеокартой в корне отличается от того, что вы фактически с ней получите, особенно если у вас медленный процессор или мало памяти.

Простейшие методы отбрасывания ненужной геометрии

Самый простой подход к отбрасыванию вершин заключается в разделении мира на секции, при этом каждая секция будет иметь список других секций, которые можно увидеть. Тогда вы сможете отображать только то, что можно увидеть с каждого конкретного ракурса. Однако создание списка видимых секций - задача нетривиальная. И опять же, она решается несколькими способами: BSP деревьями, порталами и т.д.

Я уверен, что вы уже встречались с термином «BSP деревья» при разговорах о Doom или Quake. BSP означает Binary Space Partitioning - двоичное разделение пространства. Данный метод разделяет мир на маленькие секции и группирует полигоны мира таким образом, чтобы легко можно было определить, что видно и что не видно. Такой метод полезен для программных визуализаторов, которым не нужна прорисовка лишних геометрических объектов. Побочным следствием BSP деревьев является то, что вы легко можете определить место, где вы находитесь в мире.


Движок, использующий порталы (первым таким движком в игровом мире стал Prey от 3D Realms) строится на базе создания собственной модели каждой местности (или комнаты), при этом через двери (или порталы) в каждой секции можно видеть другую секцию. Визуализатор отрисовывает каждую секцию индивидуально, как разные сцены. Впрочем, хватит теории. Достаточно сказать, что подобная работа является просто необходимой для каждого визуализатора. Некоторые методы подпадают под «отбрасывание ненужной геометрии», некоторые нет, но все они призваны решить проблему избежания ненужной работы на достаточно ранней стадии. Что касается стрелялок от первого лица, где в поле зрения обычно находится множество треугольников, и игрок сам управляет ракурсом своего зрения, очень важно, чтобы лишние треугольники, которые он не может видеть, были отброшены. То же самое относится и к космическим симуляторам, где вы можете видеть очень далеко - там следует отбрасывать все лишнее дальше области видимости. Для игр, где ракурс фиксирован, скажем для стратегий реального времени, отбрасывание реализуется несколько проще. Часто эта часть визуализатора реализуется программно и не использует карту, но через некоторое время карта сама будет все это делать.

Простейший графический конвейер

Давайте вкратце опишем основные ступени графического конвейера, от игры до отображения полигонов.
  • Игра определяет, какие объекты сейчас задействованы, какие модели они имеют, какие текстуры они используют, что с ними будет происходить дальше и где они находятся в мире. Игра также определяет местоположение камеры и ее направление.
  • Игра передает информацию визуализатору. В случае моделей, визуализатор должен сначала оценить размер моделей и местоположение камеры, и затем определить, будет ли модель вообще присутствовать на экране, находится ли она слева от зрителя (от камеры), сзади, или она настолько удалена, что ее вообще не видно. Визуализатор может даже использовать некоторый способ описания мира для нахождения видимости модели (смотрите следующий пункт).
  • Система визуализации мира определяет, где в мире находится камера, и какие секции/полигоны мира видны в поле зрения камеры. Все это можно осуществить многими способами, начиная от самого простого и прямого метода разделения мира на секции и описания «я могу видеть секции A, B и C из секции D» для каждой секции до более элегантных BSP деревьев. Все полигоны, проходящие через тест отсечения лишней геометрии, передаются визуализатору полигонов.
  • Для каждого полигона, передавшегося на визуализатор, визуализатор осуществляет трансформацию полигона в соответствии с локальной математикой (то есть анимацией модели) и математикой мира (местоположения модели по отношению к камере). Затем полигоны исследуются на предмет наличия нелицевых полигонов (находящихся на невидимой стороне объекта). Нелицевые полигоны опять же отбрасываются. Оставшиеся полигоны освещаются в соответствии с действующими световыми источниками. Визуализатор затем смотрит на то, какие текстуры полигон использует и удостоверяется, что API/видеокарта будет использовать те же текстуры для отображения. Затем полигоны направляются на API рендеринга и затем на видеокарту.

Возможно, подобное описание слишком примитивно, но зато оно дает вам общее представление. Ниже приведено более подробное описание конвейера.

  1. Приложение/сцена
    • Прохождение по базе данных сцены/геометрии
    • Передвижение объектов, нацеливание и смещение поля зрения камеры
    • Анимационные движения моделей
    • Описание содержания 3D мира
    • Проверка видимости объекта, включая по возможности отбрасывание перекрытых полигонов
    • Выбор уровня детализации (LOD)
  2. Геометрия
    • Трансформация (поворот, трансляция, масштабирование)
    • Трансформация из пространства модели в пространство мира (Direct3D)
    • Трансформация из пространства мира в видимое пространство
    • Проекция поля зрения
    • Простейшее отбрасывание невидимых полигонов
    • Отбрасывание нелицевых полигонов (может быть сделано и позже в пространстве экрана)
    • Освещение
    • Разделение перспективы - трансформация в усеченное пространство
    • Отсечение невидимых на экране частей (в соответствии с областью видимости)
    • Трансформация в пространство экрана
  3. Настройка треугольников
    • Отбрасывание нелицевых полигонов (может быть сделано и раньше перед освещением)
    • Вычисление наклона/дельты
    • Преобразование строк развертки
  4. Рендеринг/растеризация
    • Затенение
    • Текстурирование
    • Туман
    • Проверка альфа-прозрачности
    • Буфер глубины
    • Сглаживание (опционально)
    • Отображение

Как правило, вам нужно сгруппировать все полигоны в некоторое подобие списка, а затем отсортировать список по текстурам (чтобы вам нужно было загружать текстуру в карту только один раз, а не каждый раз с каждым полигоном) и т.д. Затем полигоны должны быть отсортированы по расстоянию от камеры, и самые далекие должны быть отображены первыми, но сегодня, с повсеместным использованием Z-буфера, это уже не так важно. Исключением, конечно, являются прозрачные полигоны. Они должны быть отображены после всех непрозрачных полигонов, чтобы та часть сцены, которая лежит за ними, корректно показывалась. При этом вам, очевидно, все равно придется отображать полигоны в порядке от дальних к ближним. Но обычно в стрелялках от первого лица не слишком много прозрачных полигонов. Конечно, они там могут быть, но по сравнению с теми полигонами, которые не имеют альфы, их количество очень мало.

Как только приложение передало сцену API, API начинает использовать аппаратную трансформацию и освещение (T&L), которая сейчас уже повсеместно используется в 3D картах. Мы не будем здесь подробно описывать матричные вычисления, упомянем лишь, что трансформация позволяет 3D карте отрисовывать полигоны (или что вы там хотите отрисовать) под правильным углом и в правильном месте мира относительно ракурса камеры в данный момент.

Для каждой вершины здесь производятся очень сложные операции, включая отсечение (clipping) для определения, является ли полигон действительно видимым, находится ли он за экраном или показывается лишь частично. Освещение определяет, насколько яркой должна быть текстура, в зависимости от того, как свет падает на данные вершины и под каким углом. Раньше все эти операции выполнял процессор, но современные видеоускорители переложили их большей частью на себя, так что процессор в это время может заняться другими важными делами. Конечно, все это прекрасно, но поскольку не все карты оснащены аппаратным T&L, вам все же придется писать эти процедуры самому (не забывайте, что мы опять же отражаем точку зрения разработчика).

Патчи (поверхности высокого порядка)

Помимо треугольников сейчас все чаще начинают использоваться патчи. Патчи (так называют поверхности высокого порядка) - это хорошее изобретение, поскольку они могут описать геометрию (как правило, это геометрия, состоящая из кривых) с помощью математической функции. Сравните одну функцию с кучей полигонов, где вам необходимо будет описывать еще и их позиционирование. Благодаря патчам по функции вы можете создать (и деформировать) сетку полигонов на лету, а затем решить, сколько полигонов вам на самом деле нужно получить от патча. К примеру, вам нужно описать трубу. В вашем мире огромное количество этих труб. В некоторых комнатах, где вам уже нужно отобразить 10 000 полигонов, вы можете сказать: «Хорошо, пусть у этой трубы будет 100 полигонов, поскольку в этом месте и так этих полигонов выше крыши, так что не будем жертвовать частотой кадров». Но в другой комнате, где всего 5 000 полигонов, вы скажете «Ну а теперь путь у этой трубы будет 500 полигонов, потому что мы не подошли к пределу количества полигонов на этом кадре». Все прекрасно, но не забывайте, что вам сначала нужно все это просчитать и построить сетку. А это далеко не тривиальная задача. Но с другой стороны, мы получаем хорошую экономию при отсылке функции патча по AGP против загрузки шины массой вершин для описания того же объекта. SOF2 использует патчи при построении ландшафта.

К тому же у ATi сейчас используется интересная технология TruForm, которая может преобразовать модель, построенную из треугольников, в модель на основе поверхностей высокого порядка, а затем вновь преобразовать ее в модель из треугольников, многократно увеличив их число. Затем эта модель будет отослана на конвейер для последующей обработки. ATi как раз добавила ступень TruForm перед T&L движком. Минусом здесь является то, что вы не можете контролировать, какие поверхности следует обработать, а какие - нет. Ведь некоторые грани вам все же нужно оставить четкими. К примеру, не будет ничего хорошего, если ваш нос будет плавно переходить в лицо. Однако технология достаточно перспективна, и мы наверняка увидим ее совершенствование в будущем.

На этом первая часть закончена. Во второй части вы узнаете об освещении и наложении текстур.

Следующая страница →
 
⇣ Содержание
Если Вы заметили ошибку — выделите ее мышью и нажмите CTRL+ENTER.
Материалы по теме
⇣ Комментарии
window-new
Soft
Hard
Тренды 🔥