Оптимизация Графики. Интересный Вогнутый Корпус

В какой-то момент во время разработки игры я столкнулся с проблемой производительности на современных ПК.

У нашего моделлера есть довольно мощный современный компьютер красного цвета.

Но наш проект жутко тормозил, нагружая одно ядро процессора.

Причина проста — новые процессоры имеют много ядер, но по факту они менее производительны в однопоточных приложениях.

В то время у меня был однопоточный рендеринг.

Но на самом деле причина была не столько в этом.

И в процессе поиска проблемы я решил посчитать, сколько полигонов присутствует в сцене:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

На средней игровой карте, на максимальном расстоянии и с большим скоплением пальм - 15 824 756 треугольников! Почти 16 миллионов! Огромное количество.

Немного поигравшись с генератором карт, мне удалось найти место с 16,75 миллионами:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

Хотя подобное место с елками дало всего 8,5 миллионов треугольников:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

В среднем сцена состояла из ~4 миллионов:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

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

Решение было на поверхности:

  1. Оптимизируйте количество полигонов в моделях.

  2. Оптимизируйте полигональную сетку ландшафта.

  3. Реализация многопоточного рендеринга.

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



1. Оптимизация количества полигонов в моделях

В нашем движке растительность рисуется «пачками», весь ландшафт разбит на тайлы и субтайлы, минимальный пакет — один субтайл.



Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

Один пакет — это одна сетка, поскольку уменьшение количества сеток значительно снижает количество вызовов CPU-> GPU.

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

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

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

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

В результате нам удалось сократить количество полигонов на одной упаковке елок в среднем на 40%.

Различия практически незаметны:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

С пальмами было сложнее, но паки по 5000 - 6000 полигонов нужно было подправить.

Как добиться массивности и густоты джунглей? Высокая густота джунглей достигнута за счет большого количества пальм:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

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



Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

Уменьшение количества полигонов в 10 раз — отличный результат.

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус



2. Оптимизация полигональной сетки ландшафта.

Изначально сетка ландшафта выглядела так:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

На скриншоте показаны ровные участки ландшафта, это тайлы лугов, равнин и даже других ровных поверхностей.

Я решил убрать некоторые мелкие неровности ландшафта.

Тем самым увеличивая площадь плиток равной высоты.

Просто проверив все вершины тайлов и субтайлов на одинаковую высоту, мне удалось добиться следующего результата:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

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

Была взята плитка и все ее треугольники рассортированы на массив треугольников неравной высоты и на список массивов, состоящий из треугольников одинаковой высоты и соседних треугольников.



Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

В приведенном примере результатом было: 1 массив треугольников, которые нельзя было изменить, так как все они были разной высоты (красные треугольники) и список, состоящий из двух массивов треугольников одинаковой высоты (массивы заполнены цветом ).

Теперь стояла задача найти из массива треугольников их выпукло-вогнутый контур (Concave Hull), причем многие треугольники могли иметь дырки.

Раньше в своей работе я сталкивался с выпуклыми контурами (Convex Hull), проблем с ними не было, я уже использовал алгоритм Грэма (сканирование Грэма).

Но с постройкой Concave Hull возникли проблемы.

Найти информацию на эту тему в Интернете оказалось довольно сложно.

Пришлось писать реализацию алгоритмов с нуля.

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

Но все предложенные алгоритмы давали приблизительный результат с некоторой погрешностью.

После недели мучений и боли у меня возникла идея собственного алгоритма.

Я попробовал построить контур, используя множество вершин треугольников, т. е.

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

Но для моей задачи этого не требовалось.

По моим выводам, снаряд было проще построить непосредственно из треугольников, а точность вогнутого корпуса составила 100%.

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

Далее формируется список таких ребер с учетом удаления одинаковых ребер.

Находим ребро с наименьшими X и Y и оттуда начинаем проход/сортировку ребер, попутно добавляя в список уникальные вершины.

Этот список будет оболочкой набора треугольников.

Единственное, что в итоге, — это удалить из полученного списка коллинеарные точки.

В результате я мог построить Вогнутый Корпус практически любой сложности.

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

Далее я получил контур и триангулировал его:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус



Оптимизация графики.
</p><p>
 Интересный вогнутый корпус



Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

Все получилось великолепно:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

Но в итоге я был расстроен результатом.

Разработанный мною алгоритм дал заметный прирост производительности при рендеринге сцены, так как количество полигонов сократилось в среднем на 60 – 70%.

Но при этом генерация карт стала происходить в 10 раз медленнее.

Алгоритм оказался очень трудоемким.

На продумывание облегченной версии алгоритма оптимизации полигональной сетки ландшафта ушло три дня, что дало следующие результаты:

Оптимизация графики.
</p><p>
 Интересный вогнутый корпус

Теперь расчеты данных для оптимизации стали незаметны на фоне генерации карт, а количество полигонов уменьшилось в среднем на 40-50%.

Данная статья носит предварительный и поверхностный характер.

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

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

Теги: #Разработка игр #Алгоритмы #java #open gl #Вогнутый корпус

Вместе с данным постом часто просматривают: