[Перевод] О 3D-графике простыми словами

Часть 1. Введение


Привет меня зовут baldurk. Я уже несколько лет работаю программистом графики, поэтому хоть я и не в коем случае не являюсь экспертом, кажется, я уже многое понимаю во всём том, что касается работы с графикой.

Идея этой серии постов уже давно витала где-то на периферии моего сознания, и снова всплыла после прочтения интересной статьи с разбором последней Deus Ex.

Мне кажется, что графика, и в особенности та сложность, какой она достигает в современных играх — это интересная тема. Очень немногим людям любопытно глубоко погружатьcя во все её подробности, но я считаю, что есть темы, которые интересны каждому. Я думаю, что большинству людей, игравших в игры, было любопытно, как получаются те или иные эффекты, или с помощью какой технологии удалось создать такую потрясающую графику в какой-нибудь новой игре.

4c83b92ad325af58966fc3742aa85a10.jpg


Есть много составляющих, необходимых для создания даже простой 3D-игры, не говоря уж о таком проекте, как Watch Dogs.

У меня есть только общее представление о том, что нужно рассмотреть в этой статье, но это будет зависеть от того, какие темы вызовут интерес. Тем не менее, основная идея заключается в том, чтобы создать общее описание того, что происходит внутри современной игры, не отпугнув при этом никого из читателей — я буду предполагать, что у вас нет знаний математики и программирования. Если вы знаете разницу между ЦП и графической картой, и отличаете оперативную память от жёсткого диска, то этого будет вполне достаточно, а остальное я объясню.
Эта статья будет развиваться в соответствии с её видеопрохождением Chip & Ironicus’s Let’s Play of Watch Dogs, чтобы немного структурировать изложение. Игра хорошо известна своей графикой (причём мнения о ней могут быть полностью противоположными), и в ней есть множество аспектов, которые можно рассмотреть на отдельных примерах. Возможно, я расскажу и о других играх.

Начну я с объяснения основ, которые почти одинаковы для каждой игры, но также я рассмотрю и некоторые техники и визуальные эффекты Watch Dogs.

Я буду использовать инструмент под названием RenderDoc, который я написал в свободное время. Он применяется для отладки проблем с графикой — инструмент позволяет разложить на часть кадр графики, и благодаря этому мы увидим, как он собирается вместе.


В этой анимации показана часть постепенно создаваемого кадра в процессе его отрисовки графической картой.

Большинство людей знает, что компьютерная графика (да и графика любого другого видео) состоит из серии неподвижных кадров, каждый из которых отображается определённую долю секунды. В кино традиционно использовали 24 кадра в секунду (frames per second, FPS), в телевидении частота примерно такая же, около 24–30 кадров. В играх FPS может быть переменчивым, потому что в каждом кадре выполняется множество работы. Падение частоты ниже 30 нежелательно, хотя и случается довольно часто. Обычно верхним пределом для консольных игр является 60 FPS. Разработчики стремятся реализовать частоту 30 или 60, что зависит от целей игры. На PC при наличии дисплея с высокой частотой кадров можно добиться 90, 120 или даже выше. Причина этих конкретных чисел заключается в вертикальной синхронизации (vsync), о которой мы расскажем ниже.

Мысленно мы можем взглянуть на эту задачу с противоположной стороны — вместо того, чтобы смотреть, насколько высока частота FPS, мы смотрим на то, насколько мало время, выделенное на каждый кадр. Если мы хотим, чтобы игра работала с частотой 30 FPS, то на выполнение всей необходимой для кадра работы у нас есть только 33 миллисекунд. При 60 FPS время в два раза меньше — около 17 миллисекунд. Даже для компьютера такой промежуток времени не очень велик, учитывая тот объём работы, который нужно выполнить. Чтобы дать вам представление о величинах, то по приблизительным подсчётам пуля перемещается примерно на 1 метр в миллисекунду.

В основном мы будем говорить о PC, потому что эта платформа открыта, и я не могу рассказывать о консолях без опаски нарушить соглашения о неразглашении (NDA). Всё равно в основном я буду рассказывать о том, что не сильно отличается на консолях, а если что-то всё-таки будет отличаться, то я подчеркну это. Что касается мобильных платформ, то большинство различий между оборудованием PC/консолей и мобильного оборудования не относится к теме моей статьи.

d8a414db8e56c45fae566b8da11316e2.jpg


Честно говоря, я поставил сюда эту картинку, чтобы вы понимали, что в статье будет не только текст.

Именно эта задача нас и интересует — мы не будем беспокоиться о том, как выполняет все свои вычисления ИИ, или как производится физическая симуляция для перемещения объектов. Границы дисциплины под названием «программирование графики» довольно размыты, но я скажу, что программирование графики начается тогда, когда у нас есть вся информация, необходимая для построения кадра: мы знаем, что происходит, все текстуры и модели находятся в памяти (не на диске), анимации уже анимированы, физика посчитана, и нам осталось отрисовать готовый кадр для отображения на экране.

Добавлю, что я буду рассматривать 3D-игру с достаточно традиционным рендерингом, наподобие Watch Dogs — многие из базовых принципов применимы и к 2D-играм, но на них демонстрировать концепции немного сложнее. Также поясню (особенно программистам графики), что в первую очередь стремлюсь к пониманию, поэтому, возможно, буду использовать достаточно сомнительные объяснения, если они позволят мне достичь своей цели.

Часть 2. Из чего состоит кадр


Большую часть времени мы будем рассматривать всего один кадр и рассказывать о строительных блоках, которые использует игра для создания готового кадра. Также в этой части появится несколько новых красивых картинок.

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

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

87447d95ee62161dc63df6e3dd2406f5.jpg


a3b9ecb6984a5aae18fd57d8c2f4a9f2.jpg


1e6bd2ff7c49373dc337d20c0fe2a66a.jpg


fa45cb65dfcb2042ecfd06ef6c463022.jpg


3d94ed937c68dd821ab21c4a1a1cf4fb.jpg


a573602e8f7b69fa3868df93eebc776f.jpg


Разные примеры промежуточных изображений, используемых при построении кадра Watch Dogs.

В этой статье я не буду рассматривать каждое из изображений, использованных в кадре Watch Dogs, а расскажу только об основных, чтобы вы могли чему-то научиться. Это область, в которой постоянно происходят исследования графики и возникают новые техники. Инновации возникают и на более мелких уровнях, но когда маркетинг говорит вам о какой-то новой графической функции, то обычно имеется в виду именно подобные усовершенствования.


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

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

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

35703d382d727d1e395283a4fb3aae33.jpg


Это 3D-модель головы Эйдена Пирса после анимирования. Треугольники видны, потому что они отрисованы плоскими, а не сглажены, как это бывает обычно.

Чтобы добавить на 3D-модель больше деталей, накладываются текстуры. Текстуры — это обычные плоские файлы изображений, обычно квадратные или с простыми размерами, например, прямоугольники с соотношением 2:1. Текстуры накладываются на 3D-модель с помощью более сложного процесса, который я подробнее рассмотрю ниже, но концептуально он похож на процесс заворачивания подарка. Вместо простого повторяющегося узора бумажной обёртки, изображение точно соответствует размеру обёртки. Если вы видели бумажные модели для сборки при помощи клея, то принцип здесь такой же.

Эта аналогия более уместна, чем можно подумать, потому что эти текстуры обычно создаются «разворачиванием» 3D-модели в плоскую заготовку, как это делается с бумажной моделью, после чего поверх неё рисуется текстура. Такое разворачивание часто выполняется автоматически, но в случае особо сложных объектов может производиться вручную.

b9f1f7cf0d34680c8f313ad11691656f.jpg


Это текстура, соответствующая показанной выше модели головы Эйдена Пирса. Тут есть части для зубов и языка. Заметьте, что область над его лбом не текстурирована, потому что постоянно закрыта Легендарной Бейсболкой Эйдена Пирса™.

Примечание


При разворачивании некоторые части объекта, требующие большей детализации, увеличиваются, а другие — уменьшаются.


Очень часто говорят о различных «скинах» моделей, особенно в случае настраиваемых персонажей. Сегодня то, что называют «скином», обычно относится к небольшим изменениям в модели — новый ремень или другая шляпа —, но изначально этот термин возник, потому что использовалась одна и та же модель, но менялась текстура (или «скин» — буквально переводится как «кожа») для создания персонажа, выглядящего иначе. Даже сегодня с помощью таких текстур можно создать большую вариативность NPC или объектов, что экономит время и деньги — не нужно создавать множество уникальных 3D-моделей. Разная одежда, которую может надевать Эйден — это чаще всего просто различные текстуры одной и той же модели.
Вот краткий фрагмент поворота головы 3D-модели. Наложена только текстура, и ничего более.

В рассматриваемом нами кадре есть примерно 1700 объектов, отрисовываемых в части основного рендеринга. Некоторые из них будут одинаковыми моделями — такие объекты, как цветы в горшках и мусорные баки на самом деле никогда не создаются по отдельности, это одна модель или несколько моделей, размещаемых в разных местах. Однако примерное количество отрисовываемых для завершения кадра объектов близко к 4700 — это даёт нам представление о том, сколько дополнительной работы необходимо выполнить кроме отрисовки всех этих моделей.

Давайте взглянем ещё на один пример объекта — бейсболку, которую носит Эйден.

aa21ce63666b4636b76ebe062f7536ca.jpg


0f74d3b9305c6ed4572a5bc55d178a11.jpg


Это текстура и затекстурированная модель бейсболки. Видно, что текстура построена из отдельных частей, которые соединяются на модели.

Примечание


Козырёк и основная часть бейсболки на текстуре никак не касаются, потому что развёртка может быть довольно сложной и при необходимости может выполняться в нескольких разных частях. Иногда для текстурирования модели сложной формы без видимых проблем и швов требуется изрядное мастерство.


Те же самые принципы, которые мы видели в случае головы Эйдена, относятся и к кепке. На самом деле, если абстрагироваться от конкретной текстуры и чисел, необходимых для выполнения разворачивания, то принцип всегда одинаков.

Чтобы показать, что может пойти не так при разработке, и продемонстрировать, как можно повеселиться при программировании графики, мы можем провести небольшой эксперимент. Так как большинство текстур имеет стандартный квадратный размер, а способ заворачивания и разворачивания текстур на модели тоже одинаков, то почему бы немного с ними не поиграть? Что случится, если мы применим текстуру головы Эйдена к модели бейсболки?

2121b15c7f8355575864f9333c9eeab0.jpg


Уже не очень похоже на Легендарную Бейсболку Эйдена Пирса.

Там, где на текстуре бейсболки был логотип, на текстуре головы расположены ухо и зубы. Там, где был козырёк, на текстуре головы только волосы. Наложение выполнено абсолютно так же, но использована другая текстура. Разумеется, этот пример будет в игре ошибкой, но подумайте о том, что можно сделать, если анимировать текстуру или заставить её мерцать — в играх подобные вещи используются для различных эффектов, которые теперь вы сможете замечать. В частности, игра Saint’s Row 4 использует подобное для спецэффектов «симуляции».

Также полезно будет поразмыслить о последствиях этого — игры очень тщательно сочетают пары моделей и текстур, то есть наиболее уникальным моделям должны соответствовать их собственные уникальные текстуры.

Разумеется, это правило не абсолютно — в некоторых случаях для экономии места текстура является стандартным повторяющимся паттерном, который можно использовать для множества объектов. Связанные наборы объектов — например, газетные киоски — могут использовать одну текстуру для разных газет, причём каждая газета будет занимать на текстуре небольшую часть.

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

Часть 3. Что рисовать не нужно


Часто программирование графики — это задача уравновешивания десятка разных ограничений для получения идеального компромисса. В прошлой части мы увидели, что каждый раз при отрисовке сцены она собирается из множества мелких строительных блоков — людей, автомобилей, дорожных знаков, зданий. Всё, что есть на экране, составляется из отдельных компонентов, которые необходимо отрисовать. Существует несколько тонких операций балансировки, которые мы здесь рассмотрим.

Над отрисовкой кадра совместно трудятся центральный процессор и графическая карта. В ЦП выполняется вся остальная часть игры, поэтому он принимает решение о том, какие объекты должны отрисовываться в текущем кадре, куда смотрит камера, какие анимации воспроизводятся. Графическая карта — это «рабочая лошадка», которая выполняет всю сложнейшую работу, связанную с отрисовкой пикселей, именно поэтому она является отдельным специализированным устройством.

Оказывается, и у ЦП, и у графической карты есть ограничения на скорость или объём вычислений, но это разные типы ограничений.

В целом ЦП больше интересует собственная часть работы: сколько объектов нам нужно отрисовать всего? Насколько отличаются эти объекты — это 100 одинаковых фонарей, или 100 кустов/растений/деревьев? Анимированы ли эти объекты, движутся ли динамически, и какие из них статичны или неподвижны?

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


В этой анимации мы поворачиваем камеру, показывая пустоту за игроком. Внимательные зрители заметят, что она не совсем пуста…

Сложно выработать в этом случае какие-то практические правила, но в целом можно отрисовать в сцене около 1000 объектов, не заботясь о нехватке места. Однако если нужно отрендерить 5000 объектов, то стоит задуматься о применении трюков. Не забывайте, что в большинстве игр, где игрок может управлять камерой, мы не можем знать, под каким углом он взглянет, поэтому нужно сохранять пространство для манёвра.

Оказывается, существует достаточно много хитростей, позволяющих почти полностью использовать допустимый ресурс, и особенно важны они в играх, подобных Watch Dogs. Чем ближе ты будешь к границам и чем большее визуальное качество можно получить от одинакового количества объектов, тем лучше будет выглядеть игра.

Даже если вы смотрите на то, что находится перед вами в сцене, это не значит, что необходимо отрисовывать весь город полностью. Если слева или справа есть огромное здание, то всё за ним становится невидимым, поэтому можно это не отрисовывать. Аналогично, некоторые объекты в отдалении становятся очень мелкими, поэтому нам не нужно волноваться об отрисовке крошечных растений и кустарников вдалеке.


В этой анимации показано, что если пройтись по улице дальше того, что мы видим, то в боковых улочках ничего нет, а на большом расстоянии деталей становится меньше.

На самом деле в этой сцене всё равно есть множество объектов, которые в результате окажутся невидимыми. В этой области ещё много предстоит исследовать и необходимо применять различные сложные техники. Всегда приходится идти на компромиссы, но если можно потратить немного времени, или придумать очень умный способ, чтобы избежать отрисовки 100 объектов почти без лишних усилий, то мы сможем сделать сцену ещё более сложной или плотнее заполненной.

Также здесь есть ещё одна небольшая проблема. В некоторых случаях нам приходится отрисовывать здание, которое едва видно на экране и далеко выходит за его пределы. Это тратит ресурсы впустую. Мы всегда можем разбить эти объекты на несколько частей, тогда каждую часть можно отрисовывать или пропускать, то есть пустых трат будет меньше. Однако теперь мы увеличили общее количество отрисовываемых объектов, когда они находятся на экране, и создали противоположную проблему!

Этот пример — один из сотен, но на нём легко объяснить, какие решения приходится принимать и на какие эксперименты идти, чтобы найти для каждой игры идеальную точку равновесия.

Так как действие нашего кадра из Watch Dogs происходит в городе, мы можем взглянуть на него сверху, чтобы приблизительно понять, что же именно отрисовывается. На этой статичной картинке особенно заметно, что Watch Dogs выполняет работу поквартально.


Теперь мы отдалимся, чтобы показать видимую область перед камерой (простите за монтаж для экономии времени).

7199601359a0d421147d9f632061bfaf.jpg


На изображение наложена примерна область видимости камеры. Ширина этого треугольника зависит от зоны видимости (Field of View) — иногда в играх это настраиваемая опция, иногда постоянное значение.

ccf5ffd455dccf7098393602c9944139.jpg


Вот каркасное отображение сцены, область видимости камеры ограничена белым.
Кто-нибудь из вас уже мог подумать о небольшом трюке, который бы позволил обойти ограничение отрисовки определённого количества объектов — почему бы не сделать объекты очень сложной комбинацией всего в небольшой области, вплоть до отдельных листьев? Тогда отрисовки 1000 объектов будет более, чем достаточно.

Но здесь мы сталкиваемся с совсем другим набором ограничений — графические карты имеют ограниченную производительность, и чем сложнее объект, тем дольше будет происходить его отрисовка. То есть даже один объект, если он достаточно сложен, может снизить частоту кадров игры до 20 FPS. В том числе и поэтому я говорил, что ограничение на количество объектов довольно нечёткое.

Объём временных затрат на объект зависит от сложности и детализированности моделей и текстур, а также от изощрённости освещения и теней. В том числе и поэтому игры, пытающиеся реализовать более сложную или изощрённую графику стремятся к использованию менее сложных и детализированных сцен — уравновешивание смещает весы в одну или другую сторону, поэтому можно обеспечить себе больше пространства для манёвра, пожертвовав тем, что не так важно для игры.

45f2d5233fe8bd806ab2fbf18baa038d.jpg


Это своего рода тепловая карта, демонстрирующая, в каких частях сцены есть особо сложные модели. Заметьте, сколько проблем могут вызывать деревья и растительность.

Есть ещё один набор техник под названием «уровни детализации» (level of detail, LOD), который специально создан для решения подобных проблем. Аналогично тому, что мы можем оптимизировать количество объектов, отсекая всё ненужное, мы можем увеличить запас «сложности», устранив лишнее.

Один из приёмов на самом деле хорошо известен — это изменение разрешения текстур. Эта тема обычно пересекается со множеством других, поэтому я постараюсь объяснить её доступно.

Текстуры в играх обычно являются прямоугольниками с размерами, равными степени двойки — 512, 1024, 2048, 4096. На то есть множество причин, но одно из преимуществ этого заключается в том, что можно взять текстуру размером 1024×1024 и запросто создать её уменьшенную версию размером 512×512.

По причинам, о которых я расскажу ниже, всегда необходимо, чтобы у текстуры были всевозможные версии меньшего размера. То есть у текстуры размером 1024×1024 будут уменьшенные версии размером 512×512, 256×256, 128×128, 64×64, 32×32, 16×16, 8×8, 4×4, 2×2 и 1×1. Однако одно из преимуществ этого в том, что если далёкие объекты имеют на экране небольшой размер, то накладывать на них текстуру 1024×1024 — значит зря тратить ресурсы. Мы можем сэкономить, использовав меньшие версии той же текстуры.

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

Примечание


Обычно, когда игрок приближается к объекту, используется наибольшая текстура, но как видело большинство людей в той или иной игре, такое происходит не всегда и текстуры перед загрузкой выглядят излишне размытыми. Обычно так происходит потому, что текстуры невозможно загрузить с DVD или жёсткого диска сразу в память графической карты для рендеринга. Чаще всего такое случается, когда игрок резко меняет своё положение, например, при респауне, загрузке нового уровня или очень быстром движении. Во всех остальных случаях текстуры обычно загружаются постепенно, в процессе перемещения игрока по миру.


Также можно применить этот процесс упрощения и к используемым в игре моделям, хоть сделать это и гораздо сложнее. Создавая упрощённые версии сложных объектов, можно сделать так, чтобы на большом расстоянии они не отъедали часть ограниченного запаса сложности.

Благодаря упрощённым объектам и обрезанным моделям можно сильно сэкономить и такой подход приходится использовать в любой игре наподобие Watch Dogs. Но в то же время он может быть огромной растратой ресурсов. Необходимо принять очень продуманное и взвешенное решение о том, сколько потребуется упрощённых версий моделей. Если их будет слишком мало, то вам или не удастся слишком много сэкономить, или будет заметны скачки качества при их смене. Если их будет слишком много, то вы впустую займёте память и потратите человеко-часы, необходимые на создание объектов.

801f019ed8c365cfebbbeea2320bf3d7.jpg


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

В предыдущей части я сказал, что расскажу о том, почему очень сложно правильно реализовать отражения и другие подобные вещи. Причина довольно проста — запасы производительности и ресурсов, о которых я постоянно твержу, не меняются в зависимости от того, есть у вас отражения или нет. Если вы хотите создать отражение, которое может снова отобразить всю сцену, то придётся заново выполнять всю ту работу, о которой я говорил. Кроме того, отражения очень сильно зависят от того, под каким углом мы на них смотрим, поэтому для получения точных отражений у каждого отражающего объекта они должны быть своими!

Это очень быстро может выйти из под контроля, и обычно игры, в которых есть отражения, позволяют себе определённые вольности или допущения. Игры очень редко создают отражения в сложных окружениях, максимум, что это может быть — зеркало в ванной комнате, где объектов не так много, сложность сцены мала, а потому можно позволить себе лишние траты. Возможно, истинные отражения в игре будут только на неровных или волнистых поверхностях воды, чтобы даже очень грубой и низкодетализированной сцены вполне достаточно для создания убедительных отражений.

Обычно полностью избежать отражающих поверхностей сложно, поэтому в играх используются заранее отрендеренные изображения ближайшего окружения, что даёт «достаточно хороший» результат. Но они не выдерживают пристального изучения, и если внимательно посмотреть на отражения, то вы увидите, что это имитация. Существуют современные техники, помогающие создавать отражения в определённых условиях, и возможно позже я о них расскажу, но такие заранее отрендеренные («пререндеренные») изображения всё равно нужны.

06c9bdb94b41c1a83b7d574cdf90f449.jpg


Это пререндеренное изображение называется «кубической картой» (cube map). Оно не совсем точно относительно места, в котором стоит Эйден, но достаточно к нему близко.

Watch Dogs выполняет рендеринг отражений в реальном времени. Я не исследовал этот вопрос подробно, но полагаю, что они всегда рендерятся, когда персонаж находится на улице, и в основном используются для того, чтобы получать его точные отражения на автомобиле, в котором он сидит, чтобы улучшить изображение и придать ему лёгкое ощущение реальности. Так как игрок всегда сосредоточен на своей машине и ближайшем окружении, то факт неправильности отражений на других автомобилях едва заметен.

Существует множество аппроксимаций для ускорения рендеринга этих отражений. Например, в отражении рендерится намного меньше объектов, чем есть в настоящей сцене — всего около 350 — и из них многие очень упрощены по сравнению с полными версиями. Я подозреваю, что сложные объекты, например люди, полностью отбрасываются вне зависимости от расстояния, но эту теорию я не проверял. Кроме того, на этих объектах нет теней, а освещение очень простое — только то, что поступает от солнца и неба. Отражения рендерятся с земли как в объективе «фишай», то есть отражения самой земли невозможны, а то, что находится рядом с ней, имеет очень низкую детализацию.

Но даже при всех этих упрощениях отражения справляются только с тем, что было задумано. Если проехать под рельсами, то можно получить правильное отражение с видом над автомобилем, чего на практике добиться не получилось бы.

Это решение было намеренным и принималось непросто. Запас — величина постоянная, поэтому если оставить место для этих отражений, то нужно принести в жертву что-то ещё.

ab1cdafcde2ca5c15111ca30f5b6bb5f.jpg


Вот очень «фишайное» отображение сцены вокруг Эйдена с видом снизу, сделанное для отражений. Сориентироваться можно по двум фонарям и рельсам поезда.
Есть ещё одна часть работы, которую я хочу здесь упомянуть — тени. Позже я планирую рассказать о том, как работают тени, потому что это интересная тема, но сейчас самое важное — запомнить, что тени очень похожи на отражения. Каждый источник освещения, отбрасывающий тень, должен отрендерить изображение сцены со своей точки обзора. На этот раз способов упростить работу не так много — для правильного вычисления теней каждый источник освещения обязан иметь это изображение.

Примечание


Здесь я говорю только об освещении, вычисляемом во время игры. Раньше часть освещения вычислялась пререндерингом всей необходимой информации до запуска игры, то есть тени и освещение «запекались» в уровень, они были постоянными и их невозможно было менять или реагировать на них динамически. Такая техника в современных играх используется не так часто, и очевидно, что её нельзя применять к подвижным источникам света.


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

К сожалению, это один из случаев, когда Watch Dogs не может служить хорошим примером. Расчёт теней в игре довольно сложен и, как мне кажется, специально оптимизирован для случая отбрасывания теней в городе. Поэтому я лучше переключусь на Far Cry 4 и рассмотрю вычисление теней на примере кадра из этой игры.

21c4a4ae665924ba44245b8e18249f8b.jpg


Вот сцена из Far Cry 4, которую я использую просто для примера.

7ae50226c3cc0c40c916c58f26ba27f3.jpg


Вот изображение с информацией о тенях этой сцены — для каждого из них требуется совершенно новый рендеринг сцены.

Поэтому когда нам нужно добавить к источнику освещения отбрасывание теней, то придётся отрендерить сцену ещё один раз. Здесь тоже можно использовать некоторые из аппроксимаций, применяемых в случае отражений, только их намного меньше. Можно пропускать мелкие или далёкие объекты, но нужно учесть, что эти объекты будут казаться не отбрасывающими тени. Можно отрендерить изображение очень маленьким, но тогда тени будут зернистыми и низкодетальными. Обычно не получается использовать очень упрощённую версию объекта, потому что тогда будет казаться, что объект отбрасывает тень сам на себя, или появятся просветы между объектом и его тенью.

Ещё одно следствие, которое очень легко упустить — необходимость создания изображения затенения для каждого источника освещения. Во многих случаях удаётся упростить источники освещения, объединив их — в Watch Dogs такое происходит с фарами автомобилей.

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


Основное, что я хотел подчеркнуть всем этим — это компромиссы. Мы совершенно точно можем избавиться от всех этих аппроксимаций, но придётся потратить на это наши запасы ресурсов, то есть пожертвовать чем-то другим. Каждый разработчик игр должен решать, над чем ему важно сосредоточиться в игре, и что будет наиболее впечатлять или сильнее всего раздражать игрока.

Часть 4. Двигаем вершины


В этой части я подробнее расскажу о технических деталях анимирования объектов в сцене.

Программисты графики часто говорят о «графическом конвейере» (graphics pipeline). 3D-графика немного напоминает сборочный конвейер с чётко заданным перемещением от одного этапа к другому, однако она не работает одновременно только с одним объектом.

Все современные графические карты имеют приблизительно одинаковый конвейер, у них есть специальное оборудование и ПО, прошитое непосредственно «в кремнии», для максимального ускорения

© Habrahabr.ru