Почему графика состоит из треугольников? Разбор
Все объекты в реальном мире состоят из частиц — молекул и атомов. А в виртуальном 3D-мире из треугольников, то есть полигонов.
Так статуя, созданная на движке Unreal Engine 5, состоит из 33 миллионов полигонов. Выглядит невероятно реалистично и на глаз отличить от реального мира невозможно.
Но. Почему треугольники? Хотя на самом деле не только они. Сегодня разберемся, как устроен 3D-рендер, каким образом единички и нолики превращаются в потрясающие миры, объемная объекты отображаются на плоском экране? Тут куча всего интеренсного.
Хранение
И начнем с чайника. Это один из эталонных объектов в компьютерной графике. Благодаря своей форме он хорошо подходит для тестов разных поверхностей. Чайник — это что-то вроде программы Hello World! среди программистов. Давайте сперва давайте поймем, как трехмерный мир видит компьютер?
В 3D-мире всё состоит из точек. Отличие этих точек от тех, что в 2D, наличие дополнительной координаты Z. То есть чтобы создать точку в 3D мире нужно 3 числа, X, Y и Z, длина, высота и ширина.
К примеру посмотрите на эту картинку. Таблица хранит координаты каждой точки, из которой состоит куб. Каждая строка в таблице хранит одну точку. А вот так выглядит файл с 3D точками. То есть текстовый файл с кучей координат.
Но, чтобы создать объект, одних точек не достаточно, поэтому давайте проведем линию из точки A в точку B. Но одной линии тоже не хватает, давайте создадим третью точку и соединим её линиями с точками A и B. Теперь у нас есть треугольная поверхность из которой можно строить 3D фигуры. На первый взгляд может показаться, что фигура слишком простая, как из неё можно хоть что-то сделать. На самом деле всё.
Посмотрите на детализацию этой статуи, а теперь на то, из чего она состоит… да, треугольники. Эти детали называются полигонами и из них строится всё, что вы видите в 3D играх. Треугольник — это минимальное количество точек, используемых для создания полигона, который может загрузить видеокарта.
Взглянем на ту же картинку, но с новой таблицей. Правая таблица хранит информацию о треугольниках. Вся суть в том, что чтобы нарисовать треугольник, нам всего лишь нужно указать ссылки на 3 точки. Интересно, что треугольники не хранят сами точки, а именно ссылки на местонахождение этих точек в памяти. Это очень важно знать, дабы избежать создания лишних копий. А вот так выглядит хранение треугольников в текстовом файле. Один треугольник = 3 ссылки на точки.
Есть еще один важный момент. Кстати, обратите внимание на цифры. Координаты квадрата начинаются с нулей. Если всё начинается с одного места, объекты накладываются друг на друга. Для того, чтобы это избежать, нужно перевести положение квадрата с локальной системы координат в глобальную.
Самый простой способ — перемножить сетку 4 на 4 на координаты объекта. Вдаваться в подробности не будем, просто скажем, что перемножив сетку на координаты объекта, можно изменить его положение, вращение, размер и даже систему координат.
Только треугольники?
Но чем они так хороши? На самом деле используются не только они. Некоторые из вас, кто занимается 3D-дизайном могут возразить и сказать, что на самом деле всё состоит из прямоугольников. Тут важно отметить, что в 3D-графике ещё есть такое понятие как прямоугольный полигон, или же квад. Квады практически всегда используют при создании 3D-объектов. Причиной этому служит тот факт, что квады гораздо легче делить. При делении треугольников, могут возникнуть искажения на кривых поверхностях, как на этом снимке. Поэтому при в моделинге 3D-текстур, треугольники стараются избегать.
Но, когда 3D-модель (или ассет) создан, все квады превращаются в треугольники, так как точек меньше и математика с ними гораздо проще.
Смотрите, плоские полигоны гораздо проще рендерить, по этому они более предпочтительны. Если мы возьмем квадратный плоский полигон и изменим расположение одной точки, он перестанет быть плоским и выйдет из так называемой полигонной сетки. Из-за этой фичи, нужно проводить дополнительные вычисления, чтобы проверить плоский ли полигон или нет. Треугольники от этого не страдают, так как какую точку не перемести, треугольный полигон останется плоским. Профит.
Нюансы хранения
Также важно упомянуть Level of Detail, или же LOD. Удалённые объекты занимают очень малую часть экрана и их детали рассмотреть невозможно. Философия проста, зачем дальним объектам много полигонов, если их не видно. В кратце LOD сокращает количество полигонов на всём, что находится далеко от камеры и плохо видно.
Рендеринг
Есть одна важная вещь, о которой немногие догадываются: 3д игры на самом деле не трехмерные. Мы смотрим на них через дисплей, который плоский. И имеет только две координаты.
С хранением 3D-штук разобрались, теперь о том как превратить их в 2D изображение, которое мы видим на экране. И делать это желательно 60 раз в секунду.
Перспективная проекция
Ну начнём с того, что всё, что мы видим на экране на самом деле 2D. Определённый цвет пикселей на экране меняющийся в правильной последовательности дает иллюзию трехмерного пространства.
То есть, нам надо трехмерный мир спроецировать в плоскую картинку. Как это делается? Чтобы добиться этой иллюзии, используется техника перспективной проекции.
Эта техника создает плоское изображение 3D объектов, которое отображается на экране так, что результат кажется трехмерным.
Подход простой: удаленные объекты кажутся меньше, близкие больше. Работает это так, нам нужно спроецировать каждую точку объекта на экран в перспективе. Далее начинается школьная геометрия. мы видим такой треугольник, а точнее 2. Есть высота дерева в 3д мире — это У. Нам нужно найти значение Ys, что является высотой объекта на экране. Из уроков математики мы знаем, что боковые стороны подобных треугольников пропорциональны друг другу. Из этого мы делаем вывод, что боковая сторона первого треугольника, деленная на расстояние до экрана равна боковой стороне второго треугольника, деленного на расстояние до объекта. После перестановки, мы видим, что финальное значение равно расстоянию до экрана, деленного на расстояние до объекта, умноженного на его высоту. С иксом тоже самое, просто нужно заменить y на x.
Но на этом не всё. Чтобы объект попал на экран нам нужно совершить ещё 2 действия. Для начала перевести полученные координаты в орфографическое пространство, чтобы соответствовать плоскости наших мониторов. После чего их нужно централизовать, переведя в Vulkan’s Canonical view volume. Это уже то, что мы видим на экране.
Обрезка
Если просто забросать 3D-сцену треугольниками, может возникнуть проблема, игра начнет лагать. Благо есть читерские методы, которые позволяют легко ускорить рендер.
Например можно рендерить только те объекты, которые находятся в направлении, куда смотрит игрок. Этот способ называется frustum culling.
Слово Фрустум — это конусовидная призма, форма, которую принимает область видимости камеры.
У этого способа есть старший брат, называется occlusion culling, который работает хитрее: удаляет те объекты, которые перекрывают другие! То есть те объекты, на которые вы не смотрите — реально не существуют.
Например, можно посмотреть как это реализовано на движке анриал: в специальном режиме видно, что все объект вне зоны видимости просто пропали из сцены.
Ещё одна важная техника в 3D-рендеринге называется clipping или обрезка по нашему. Как следует из названия, всё, что не попало в угол обзора, срезается для лучшей производительности. Clipping отличается тем, что она может обрезать часть объектов.
Кстати, разница clipping’a и ранее упомянутого culling’a в том, что первый метод удаляет полигоны, которые не попали в кадр, в то время как culling удаляет сами объекты на программном уровне.
После этого, значения нужно перемножить снова, но уже на сетку окна приложения. Это нужно например если вы играете в оконном режиме.
Растеризция
Теперь финальная часть, вся графика отображается на вашем экране с помощью процесса рестаризации, который берет все эти сложные линии и формы, полученные после перспективной проекции и приближает их к тому, как должны быть окрашены пиксели. В самом простом варианте растеризации ставится точка в центре пикселя и если объект задет, пиксель окрашивается, если нет, берём пиксель с другого объекта. Но такой способ создает очень рваную и пиксельную картинку. Здесь помогают разные алгоритмы сглаживания, которые делают переходы гораздо мягче и картинка получается более четкой.
GPU
За рендер 3D-объектов отвечает GPU. Да, тот самый графический чип, который позволяет нам играть в игры 4K 120 FPS. В этом ему помогает огромное количество ядер, гораздо больше, чем у центрального процессора. К примеру у RTX 3090 10496 ядер, в то время как у ryzen 7 5800x всего 8.
И тут вы можете спросить, а что нам мешает использовать графический процессор вместо центрального, ведь в нём так много ядер, а значит он мощнее. На самом деле нет. Ядра GPU отличаются от CPU тем, что они гораздо глупее и предназначены для простых, монотонных работ с графикой. CPU же в свою очередь имеет очень умные ядра, которые способны работать над очень сложными задачами быстро и независимо друг от друга. Другими словами если ядра в графическом процессоре это муравьи, которые строят домик, их много, но работа не требует много интеллекта. То ядра в центральном процессоре это учёные, создающие вакцину от коронавируса.
Скорость современных видюх просто поражает. Например вот видео где парень рендерит 312 миллиардов полигонов на RTX 3090 в реальном времени.
Итог
На этом всё. Есть ещё много того, что мы не разобрали, к примеру трассировка лучей или Ray Tracing, Shading и Anti-Aliasing. В общем, это еще несколько интересных тем, которые можно разобрать в будущем…
Post Views: 135