Gamedev
Игорь Дятлов
7416

Оптимизация: почему время важнее полигонов

Многие начинающие 3D-художники и разработчики игр знают, что существует «оптимизация» — нечто, что позволяет повысить частоту кадров. Но зачастую они не разбираются в том, как она работает — и это заставляет их принимать неверные решения.

В закладки
Аудио

В этом материале преподаватель курса OutBlock и левел-дизайнер VOID Interactive Денис Куандыков объясняет, как устроена оптимизация, и почему количество полигонов тут — не ключевой фактор.

В чём проблема

Работая с геометрией, новичок может потратить уйму времени впустую, пытаясь сократить количество полигонов. Даже если лимит по техническому заданию позволяет определённому LOD (уровню детализации) держать в себе 10-15 тысяч трисов (полигонов с тремя сторонами), моделер может решить, что если он всё уместит в 5 тысяч треугольников, то работа станет более «оптимизированной». Это не так.

Оценить абстрактную «стоимость» рендера одного кадра невозможно — нужно знать, под какие устройства создаётся игра, и что именно в ней отрисовывается.

Если 3D-артист со стороны попытается самостоятельно оценить сложность кадра, то может получиться недоразумение. Художник не знает, какое количество треугольников будет оптимальным, если нет чёткого технического задания.

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

Как устроена отрисовка кадра

Процесс отрисовки кадра — это та самая «магия под капотом движка». У отрисовки, как и у работы художника, есть стоимость, и рассчитывается она исходя из необходимого времени.

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

Во всех движках есть вывод статистики. Самое важное в нашем случае — это значение времени одного кадра.​

«Время кадра» — это время в милисекундах, за которое может быть построен и отрисован один кадр. Чтобы получить 60 кадров в секунду, один кадр должен быть обсчитан за 16 милисекунд или еще быстрее.

Draw Call (вызов отрисовки) — это одна графическая команда, которая должна что то отрисовать.

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

И наоборот — чем меньше вызовов отрисовки, тем быстрее считается кадр, и тем выше FPS.

Frame Debugger — встроенная утилита Unity, позволяющая прямо в редакторе разобрать один кадр на все составляющие. Этот кадр занял 96 отрисовок.​

Примерный разброс лимитов на Draw Call можно описать так:

— Мобильные игры — примерно 100 на средне-высоких настройках, на топовых устройствах можно и больше.

— Игры для ПК и консолей — до 4000.

Например, Battelfield и третий «Ведьмак» в среднем работают на 1000-2000 вызовах отрисовки.

А у PUBG этот показатель скачет от адекватных цифр (до 5 тысяч) вплоть до безумных 50 тысяч Draw Call. Такой разброс — это плохо.

В то же время, некоторые внутренние движки Ubisoft спокойно работают на значениях вплоть до 20 тысяч. Дело в том, что Draw Call — это тоже не идеальное мерило производительности. Вызовы отрисовки бывают разные, и тут всё зависит от того как работает конкретный рендер-пайплайн в конкретном проекте. Подробно разобраться в том, как это устроено, можно здесь.

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

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

— RenderDoc

— Nvidia Nsight

— Intel Graphics Perfomance Analisys

RenderDoc​

Подробнее обо всех этих инструментах можно узнать здесь.

Самое важное: нужно оценивать стоимость кадра. А первичное мерило стоимости — это время. Уже затем можно всё раскладывать на процессы, то есть, на те самые вызовы отрисовки.

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

Вызовы отрисовки

Теперь разберёмся, как именно можно подсчитать количество этих вызовов.

Простой пример: у нас есть 10 ящиков и одно дерево. Все десять ящиков имеют один и тот же шейдер, материал и количество полигонов. Логично предположить, что у нас будет 11 вызовов, ведь в кадре 11 объектов.

Всё почти так и есть. Программа рендерит так: «ящик, ящик, ящик, ящик, ящик... и потом дерево. Кадр построен».

Однако, судя по статистике, у нас всего три батча (вызова отрисовки):

Дело в том, что движок сам понимает, что перед ним десять одинаковых ящиков. Он сам «сшивает» ящики в один объект, и теперь процессор отдает нашей видеопамяти на отрисовку один кусок меша, который мы видим как 10 отдельных ящиков.

Этот процесс называется «батчинг». Он бывает динамическим и статическим.

Как устроен батчинг

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

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

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

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

Статический же батчинг происходит «заранее». Для этого нужно указать что этот объект статичен, и никогда не будет изменен или сдвинут.

Отличие от динамического батчинга в том, что он позволяет перерабатывать огромное количество объектов. За один батч Unity может сшить объектов общим количеством до 64 000 треугольников.

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

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

Чтобы батчинг сработал, объекты должны быть «одинаковы». Объекты должны иметь один и тот же шейдер, материал на этом шейдере (в Unreal это инстанс материала), текстуру и остальные параметры объекта, а также не должны иметь Non Uniform Scale и не должны быть разбиты светом.

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

​Пример очень простого атласа для тайловых поверхностей.

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

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

Так например, два одинаковых ящика, которые в обычной ситуации превратились бы в один батч, разделят на два батча, так как они привязаны к разным лайт-пробам (Light Probe).

Освещение в реальном времени тоже будет влиять на то, какие объекты сбатчатся, а какие — нет.

Световые зонды (Light Probes) нужны, чтобы запечь в себя шейдинг в статичном освещении. Они позволяют затенить динамический объект в сцене с Light Map.​

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

Поэтому иногда применяют «ручной» батчинг, он же просто «мердж» (merge). Берём геометрию, и в любой программе сшиваем так, как нужно под конкретную сцену.

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

Иногда гораздо выгоднее скормить движку огромный меш в 64 тысячи треугольников, чтобы отрисовать всю локацию целиком. Так поступили, например, разработчики Guns Of Boom.

Подобный подход практически полностью исключает использование Occlusion Culling. Эта техника позволяет не рисовать те объекты, которые не видны камере. То есть, когда ящик перекрыт другим более крупным ящиком — мы его не видим, а значит можем не рисовать. В случае со «склеенными» мешами такое разделение невозможно.

Уровни детализации

Level of Detail (LOD, или уровень детализации) — простая техника, которая позволяет уместить огромное количество объектов в кадре, не отнимая время на обработку лишней геометрии.

LOD может разбить объекты на разные батчи: и в этом нет ничего страшного, ведь зачастую несколько сотен лишних DrawCall будет быстрее обсчитаны на лодированых мешах чем рисовать их оригиналы — но сбатченные.

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

Обычно используют четыре уровня детализации. LOD-0 — это оригинальная модель, а LOD-3 — дальняя. LOD4 может быть просто 2D спрайтом который всегда смотрит на игрока.

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

Это касается даже мелких объектов: например, у обычной кружки в одной из стартовых сцен Dead Space 2 было достаточно полигонов, чтобы она не казалась «квадратной», в то время как в остальной игре в LOD-0 у аналогичных объектов не было такого сглаживания.

LOD-ы позволяют не считать лишние сотни полигонов в вашей модели. В первую очередь важно понимать роль модели в сцене и прикидывать, насколько детально игрок сможет её разглядеть.

Если модель, например, можно разглядеть вблизи с максимальным приближением, то просто сделайте LOD-0 достаточно детализированным, — а в самой сцене основным рабочим уровнем будет LOD-1.

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

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

Alpha overdraw

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

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

Чем меньше альфы, тем быстрее будут обсчитаны пиксели. По сути, шейдер и сам рендер — это процесс/программа, которая рисует конкретный цвет конкретного пикселя на экране. И в этом случае пара десятков лишних треугольников, наоборот, ускорит рендер.

Cлева — обычный «плейн» с текстурой ветки. Справа — он же, но силуэт ветки обрезан по контуру, чтобы срезать лишнюю прозрачную площадь.​

Z-Fight — артефакт, который образуется, если поставить несколько полигонов в одной плоскости. Рендеру не хватает точности глубины, чтобы отсортировать отрисовку этих полигонов в правильном порядке.

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

Два плейна на одной оси. Смешение цветов по центру и есть Z-Fight.​

Итог

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

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

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

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

Время — крайне важный ресурс не только для рендера, но и для вас как для специалиста.

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

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

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

Денис Куандыков — один из преподавателей курса по левел-дизайну OutBlock, который стартует 15 апреля.

Среди других преподавателей — Михаил Кадиков (Crytek), Макс Пирс (CD Projekt Red), Елена Кондрашина (Mundfish) и Илья Иванов (CD Projekt Red).

Узнать дополнительную информацию и записаться на курс можно здесь.

Материал опубликован пользователем.
Нажмите кнопку «Написать», чтобы поделиться мнением или рассказать о своём проекте.

Написать
{ "author_name": "Игорь Дятлов", "author_type": "self", "tags": [], "comments": 107, "likes": 208, "favorites": 675, "is_advertisement": false, "subsite_label": "gamedev", "id": 101398, "is_wide": false, "is_ugc": true, "date": "Sat, 08 Feb 2020 11:21:00 +0300", "is_special": false }
0
{ "id": 101398, "author_id": 158163, "diff_limit": 1000, "urls": {"diff":"\/comments\/101398\/get","add":"\/comments\/101398\/add","edit":"\/comments\/edit","remove":"\/admin\/comments\/remove","pin":"\/admin\/comments\/pin","get4edit":"\/comments\/get4edit","complain":"\/comments\/complain","load_more":"\/comments\/loading\/101398"}, "attach_limit": 2, "max_comment_text_length": 5000, "subsite_id": 64954, "last_count_and_date": null }
107 комментариев
Популярные
По порядку
Написать комментарий...
5

Боже мой, 15 лет прошло. Будто вчера.

Ответить
12

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

Ответить
9

Впервые слышу чтобы в зибраше кто-то модели лепил для движка

Ответить
15

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

Ответить
0

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

Ответить
3

С чего ты взял что ВСЕ тридешники знают про существование только 1 этапа пайплайна? Сам только её и то не осилил?

Ответить
1

Да я вообще не представляю себе моделлера, который бы так делал. Реально человек с луны должен быть, а может даже с внешних колец Сатурна.

Ответить
5

В зебраше делают только скульпт. Больше ничего. Ох уж эти мамкины арт-директора с дтф.

Ответить
0

Лепить геймдев модели с кучей полигонов - это не "не думают об оптимизации", это "не разбираются в пайплайне и индустрии"

Ответить
1

в ассасине вон 60к отрисовок в пещере, при этом с нагрузкой на железки вроде все более менее ок, это как так вообще?) https://youtu.be/aBWenAJ0cGU?t=441

Ответить
21

В целом не все дроколлы имеют одинаковую стоимость на cpu, многое зависит от того, что делается между ними (меняется шейдер, обновляются буфферы, меняется рендер стейт, например, включается альфа-блендинг). Ну т.е. допустим есть 5 дроколлов на 2 шейдерах (s1 s2) и 3 материалах (m1,m2,m3). Пусть материалы m1 и m2  используют шейдер s1, а третий материал s2. Тогда можно дроколлы делать так:

set s1->set m1->draw1
set s2->set m3->draw2
set s1->set m2->draw3
set s2->set m3->draw4
set s1->set m1->draw5

А можно так:
set s1->set m1->draw1, draw5
set m2->draw3
set s2->set m3->draw4

Тут суммарно будет меньше изменений состояний gpu и работать это будет быстрее.(вероятно, см ниже). Батчинг в движках он не только про инстансинг геометрии, он и про такое уменьшение количества смены стейтов. Это разумеется не жесткие батчи, обычно это все решается специально сортировкой поданных на рендер объектов. При этом надо учитывать, что батчить "по жесткому" может быть не выгодно по многим причинам (early-z, например, из-за которого лучше сначала рисовать ближние объекты, и это не позволяет батчить далекие от камеры объекты с ближними). В целом тут вопрос конкретного проекта и конкретных замеров, в разных ситуациях разные решения оказываются быстрее. Это один из вариантов, которым можно повысить число дроколлов, не уменьшая время отрисовки.

Второй - использование новых апи (вулкан, дх12, апи пс4 и т.п.) Там основная фишка в том, что достаточно большая часть работы по подготовке дроколлов переносится из кода драйвера в код приложения, что позволяет не делать кучу синхронизаций, т.к. драйверу обычно неизвестно, когда приложение захочет нарисовать какой-то объект, поэтому какие-то ресурсы могут быть недоступны на момент дроколла (например, не быть в видеопамяти), это все надо проверить и исправить, если что не так (например, перетащить текстуру в память карточки или дождаться, пока освободится какая-то текстура, используемая в других отрисовках). На проверку всего этого уходит много времени, причем это почти нереально делать параллельно на нескольких ядрах. С новыми апи предполагается, что движок сам знает, в каком состоянии ресурсы, где они в памяти расположены и т.п., и драйверу не нужно делать дополнительной работы (на самом деле нужно, но сильно меньше, чем раньше). Это сильно увеличивает число доступных дроколлов. В ассасине новые апи начали использоваться очень рано, на пк это одна из первых серий, где движок по настоящему использовал новые апи и был разработан вокруг них (рендер anvil был почти полностью переписан при разработке ac:unity), поэтому там большие количества дроколлов поддержаны изначально и не настолько влияют на перформанс, как у других.

Ответить
1

Жаль нельзя два плюса в коммент оставить =)

Ответить
0

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

Ответить
2

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

А drawcalls больше зависят от cpu, чем gpu. Чтобы их забатчить в коммадный буффер, тоже требуется определенное процессорное время. На gpu они влияют скорее в том смысле, что каждый вызов может отрисовывать ту же область на экране, что уже была отрисована ранее. Но это проблема несложных оптимизаций. А на gpu влияют как раз сложность шейдеров, и их количество в конвейере, количество пикселей, которые они покрывают для каждого меша, кол-во вертексов, блендинг и прочая муть...

Ответить
0

Для пока эти меня шейдера если честно контр-интуитивны все, как и ситуация с батчингом, делающая контр-интуитивной влияние числа(!) дроуколлов на конечное время, затрачиваемое на вызовы на стороне CPU и тем более на корреляцию с шейдерной нагрузкой на GPU. Если имеются по этой теме рекомендации по литературе - был бы признателен. Мало с ними взаимодействую, но вот недавно в целях прототипирования запилил не архи какой сложный шейдер на <300 инструкций в визуальном редакторе анрила, с динамической тесселяцией на основе RT текстурной маски и с отрезанием по дистанции от камеры, и так вот сама тесселяция ничего не жрёт, но когда рендерится меш с этим шейдером - оно съедает 8мс времени на RTX 2070 ещё до того, как хоть что-то было тесселировано - ну вот просто потому что (очевидно шейдер такой тяжелый). Это конечно не про дроуколлы, но всё же...

Ответить
0

Ну, что есть 300 инструкций - это сложно сказать. Шейдер может выйти как и легким, так и невменяемым.  Можно сделать шейдер и не десяток инструкций, но в котором будет множество условий или лупов, что выйдет боком  для производительности.
Честно говоря, я не знаю многого про литературу. Главная постоянная величина в царстве постоянно обновляющихся технологий - это спецификация. 
Все это дело, действительно, не очень просто, но самое главное всегда пишут во всех туториалах: меньше материалов, меньше разной геометрии.Чем более мы усложняем пайплайн, тем тяжелее отрисовка, и наоборот.  К примеру, чтобы сделать обычный pbr 300 инструкций не нужно - приближенная brdf-функция не требует слишком многого, а функции-обвесы требуют еще меньше...
В любом случае, все выливается в компромисс: качество - производительность. Где поставить черту - это уже зависит от конкретной задачи. Здесь помогут только тесты...

Ответить
0

Про тесты оно и понятно, и аж целые 8мс жора с этого шейдера на RTX 2070 однозначно говорят о том, что это чудо в продакшн и тем более на консоли совершенно точно не пойдёт))

Ответить
0

Ага. Это инструкции, и не менее важно считать переключение сетов.
Но это уже слишком под-движковая магия которая обычному художнику не нужна.

Ответить
0

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

Ответить
0

Ключевое слово "техническому" =)

Ответить
0

Без технических художников в команде ничего кроме совсем уж низкобюджетных инди поделок и не делается ;)

Ответить
0

Я это и не оспаривал =)
Но, технические спецы и рендер-программисты это целая "каста" крутых ребят.
Обычному художнику эти детали не нужны - он должен тратить свое время на прокачку арта и качества своей модели.

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

Ответить
0

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

Ответить
0

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

Ответить
1

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

Ответить
0

Ага, ведь все это тратит !время художника впустую =)

Ответить
0

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

Ответить
0

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

"Идеальных" пайплайнов, как людей, так компаний и технологий не существует.

Ответить
3

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

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

Ответить
0

Очень "легки" дравколл, сам по себе DC это лишь команда - все зависит от того как устроен у них сам рендер пайплайн.
Тем не менее последние ассасины очень требовательны к CPU.

Ответить
0

Ну, на моем 7 летнем i5 2500К все шло на ультрах. Правда 1070 ему помогала. И проц у меня даже не разогнанный.

Ответить
0

На практике, драйвер достаточно умён, чтобы не слать команду сразу на GPU. Он может делать собственный батчинг на низком уровне. 

Ответить
0

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

Ответить
5

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

Свидетели лишнего полигона, ога))

Спасибо за материал.

Ответить
5

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

Ответить
3

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

Всё бы было хорошо, если бы не это предложение в подсвеченной врезке.

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

Ответить
0

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

А недооценивать батчинг в случае статичности уровней все же не стоит.

Ответить
0

RTX должен как раз эту проблему решить в будущем.

Ответить
3

Такую статью лучше бы рендерщик написал, потому что вы

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

и про draw-calls с новыми API все гораздо менее однозначно.

Ответить
2

Если у вас на сцене z fight то по рукам надо давать левел дизайнеру .

Ответить
0

А если Z-Fight случается со стороны партиклов дыма, конфликтующих со стеклянной поверхностью на фоне?))

Ответить
2

То колотить вфх Художника. Ах да. Они же неприкасаемые - уйдут же. Следующего фиг найдешь.

Ответить
0

Так и есть )

Ответить
1

Отличная статья, спасибо! 

И очень вовремя :3

Ответить
–1

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

Звучит как костыль. Почему не обучить движок сшивать текстуры в атласы?

Ответить
2

Есть такая технология - мегатекстура от Кармака называется. Только что-то она не получила широкого распространения.

Ответить
1

Она случайно в первом Rage не использовалась?

Ответить
2

в первую очередь она использовалась в Enemy Territory: Quake wars в 2007 году, причём игра на id tech 4 - движке от третьего Doom. И работала там отлично.

Ответить
1

У ID и Кармака всегда всё отлично работает. Только вот другие не подхватили эту тему и не стали внедрять её в свои движки.

Ответить
0

Некое подобие мегатекстуры есть во многих баттлроялях

Ответить
0

Да потому никому нахрен не сдались линейные шутеры, весящие по 50 Гб. Привет, Doom 2016 (игра-то хорошая, не воспринимайте это как критику самого наполнения игры). А теперь приложите эту ресурсозатратность к какому-нибудь Скайриму. Это же будет ужас.
А ещё мегатекстура имеет проблемы с подгрузкой тайлов (здесь: сектор для куска текстуры на статичной геометрии пространства) высокого разрешения, т.к. она воспринимает одинаковые текстуры для двух близлежащих тайлов как совершенно разные. Это, кстати, не только сказывается на нагрузке диска, но и засоряет видеопамять по-самое нехочу!
Вот видео с показанной прогрузкой: https://youtu.be/YeX-20DAA0I
И картинка с системными требованиями. Особенно неудобно, если устанавливать на SSD размером 256 Гб. Это отвратительно для шутера в относительно закрытых помещениях.

Ответить
0

Да потому никому нахрен не сдались линейные шутеры, весящие по 50 Гб

А мегатекстура тут причём?

Ответить
0

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

Ответить
0

Ну и что же тогда Rage всего 20 Гигов весит?
При этом новый Doom Eternal в котором разработчики (по их словам) полностью отказались от Megatexture по прежнему требует 55Gb?

Ответить
0

Представьте себе абсолютно одинаковые шахматные клетки, наложенные на поверхность. Так вот, если они наложены как мегатекстура, то вес самих текстур будет значителен по сравнению с текстурой, накладываемой традиционным методом. И мегатекстура будет применима только к этой карте. Но, такая технология позволяет нарисовать множество уникальных текстур (проще бывает нарисовать вариации одной и той же текстуры, соединив таковые в одну, накладывая её, где только можно) на местности. Правда, это дорого обходится как и разработчикам, так и игрокам.
Видео в помощь: https://youtu.be/BiQCz2NjPR8

Ответить
1

Вроде да. Еще в квейк 4 вроде. Кармак её продвигал очень усиленно. Но ленивые рукожопы сказали, что слишком сложно )).

Ответить
0

+ в doom 2016

Ответить
0

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

Ответить
0

раскрашивать каждую трубу и вентиляцию на картах.

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

https://youtu.be/Tsc0cTYvIPE?t=91

Ответить
0

Я думаю автор коммента говорит о "мега-текстуре", она ведь позволяет художникам уникально кисточкой любой тайл поверх перекрасить.

Ответить
0

Да я понимаю про что он. Просто он так говорит — «собственноручно БЫЛИ ВЫНУЖДЕНЫ раскрашивать»  — словно применение мегатекстуры создавало прямо какие-то невероятные неудобства и все художники рисовали киллометры уникальных текстур ручками с нуля

Ответить
0

Я итак этим всю жизнь занимаюсь. И ничего, не развалился.

Ответить
1

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

Ответить
0

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

Ответить
0

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

Ответить
1

пропихивать в продакшн плохие решения

Если бы оно было НАСТОЛЬКО плохим, то его бы перестали использовать сразу же после выхода Rage.
Плюс стоит отметить что мегатекстуры делали под системы с ограниченным объемом памяти. На Xbox360 Rage работает вполне неплохо.

Ответить
2

У тебя два стула:
1) Уникальные текстурки для объектов, которые никак больше не применить
2) Зацикленные текстурки под кучу объектов, из которых на изи собирается атлас. Движком, руками - без разницы вообще. 

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

Ответить
0

Есть ссылочка на подробности? Просто лично видел в Assassin's Creed Odyssey обычную текстуру, причем несколько штук на один объект (статуя с пенисом).

Ответить
0

Просто загугли менатекстура одиссии, даж на вики есть. 

Ответить
0

Загуглил на русском и английском - не нашел. В статьях Википедии (RU/EN) слова "текстура" вообще нет.

Ответить
0

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

Ответить
0

И я тоже не нашел, потому что это запрятано в какой-то жопе, типа дневников разработчиков на ютубе. 

Ответить
2

В данном случае, в одной фразе сразу пара  пунктов. 1) "Меньше текстурить уникальными сетами" - то есть если у тебя ящик, забор и доска, то лучше использовать одну и ту же текстуру, по возможности. 2) "отдельных текстур" - на самом деле, движки могут сшивать атласы. Могут сшивать на лету, при загрузке ,а могут и заранее. Просто не всегда автоматические решения дают нужный результат.

Ответить
1

В Unreal недавно появилась: virtual texturing называется. Правда только для landscape

Ответить
0

Какой в этом смысл? 

Ответить
0

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

Ответить
0

это и есть «преждевременная оптимизация» про которую автор статьи говорит не делать, в атлас текстуры бэйкнуть можно на финальной стадии или рантайм движком.

Ответить
0

Прекрасный материал, спасибо

Поэтому иногда применяют «ручной» батчинг, он же просто «мердж» (merge). Берём геометрию, и в любой программе сшиваем так, как нужно под конкретную сцену.

Разве статический батчинг не занимается именно этим? Я билдил свои проекты и проверял просмотрщиком ассетов для Юнити - и в ресурсах всегда находил большие меши, которые состояли из отдельных объектов, которым я назначал Static свойство, то есть, движок при билде соединяет все в один меш (что в свою очередь мешает окклюжн куллингу)

Ответить
2

Да, однако крайне сложно "приказать" движку сшить конкретные меши в статический батч - он будет ломать большой батч на разные элементы по множеству причин (те же лайтпробы например).
+ самое главное что в итоговый билд идет уровень с моделями "конструктором" из которого он собран и вместе с ним меш сбатчанный, что увеличивает вес итогового билда. 
А для мобайла вес проекта оч критичная штука, маркетологи не любят когда проект тяжелый по памяти.

Ответить
0

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

Ответить
2

Боюсь про шейдера нельзя описывать кратко, слишком уж там важны ньюансы =)
Если и писать о них, то оптимальнее привязывать конкретную ситуацию под которую сделаны конкретные шейдеры.

Ответить
–1

Lod не дает прироста в скорости а порой и уменьшает ее, если это не HLOD. 
Think about it. 

Ответить
0

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

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

Ответить
1

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

Это уже комплексный подход а я все-таки говорю о той самой системе юнити которая в данный момент крайне не идеальна и пересматривается в сторону  hierarchy lod.

https://blogs.unity3d.com/ru/2018/01/12/unity-labs-autolod-experimenting-with-automatic-performance-improvements/
Вот кстати интересная статья с тестами. Также в megacity ребята на dot's сделали рабочие лоды, очень интересно выглядит.
 
Я кстати последние дни репу чешу, сцена с объектами в, texture array намного быстрее чем просто текстуры?

Ответить
0

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

Ответить
0

Вот результаты из статьи выше, стоит учитывать что батчинг и лоды не совместимы

Ответить
0

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

Ответить
0

Спасибо за статью! Очень познавательно! <3

Ответить
0

Примерный разброс лимитов на Draw Call можно описать так:

— Мобильные игры — примерно 100 на средне-высоких настройках, на топовых устройствах можно и больше.

Открыл свою игру для мобилок, у меня 2100 вызовов...

Ответить
0

Реквестирую что вы юзаете ландшафт (террейн) вместе с его растительностью + реалтайм свет.
Даже если девайсы средне-высокого класса (аля 7 айфон) скушают это в 30 fps, то они будут как минимум дико греться и жрать батарейку.
Лоуэнд девайсы такое количество отрисовок врядли потянут.

Ответить
0

Ну, от террейна я давно избавился, но деревьев у меня всё равно дофига
Сейчас понизил графику до Good, осталось 1000 вызовов
Надо что-то делать со всем этим. Вся геометрия максимум лоуполи, в кадре не больше 500 тысяч треугольников

Ответить
0

Для деревьев рекомендую юзать что то вроде плагина Vegetation Studio (только надо настроить) ибо он позволяет рисовать чанки растительности где 1 чанк назначается на конкретную лайтпробу, из за чего рисуется ~10 отдельных деревьев рисуются в 1 батч. 
Ну и учитывая размеры мобильных экранов, использовать билборды напрашивается само по себе.

Для Фортнайта использовали "Импостеры" что бы рисовать огромные леса на фоне, но их по глупому использовать нельзя ибо они очень сильно отжирают память. Для юнити есть плагин который генерит импостеры от Amplify.

Ответить
0

Проблема в том, что у меня все деревья вручную расставлены. Карта городская, террейн там не вставишь. И все деревья не вдалеке, а вокруг.

Ответить
0

Что за движок? 

Ответить
0

Вручную расставленные деревья еще проще оптимизировать, ну и опять же Vegetation Studio с этим поможет. 

Ответить
0

Объедините меши в instanced static mesh (ISM) или hierarchical ISM.

Ответить
0

За Гнома лайк)
Самая оптимизированная модель всех времён)

Ответить
0

Всё зависит от цели, платформы, кадра, движка, всё остальное - вилами по воде писано, надо тупо мерить время рендера, те же 100 дроу колов для мобил) а время рендера кадра зависит от вообще всего что есть в игре, как игра грузится, как организована сцена, менеджмент памяти, логика, физика, рендер там в самом конце идет
Мораль - работайте по ТЗ?)

Ответить
0

Мне интересно, есть ли у вас опыт оптимизации в Unity с применением Entity Component System? Burst Compiler, Job system etc.
Насколько вообще все эти знания будут актуальные для тех, кто выйдет в продакшен в связке LWRP + ECS и есть ли такие вообще помимо самих ребят из Unity?

Ответить
0

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

(опять же экономлю всем время)

Ответить
0

Прочитал это все и понял на сколько автор не понимает всего вышеперечисленного. Про z-fight и писекилей которые спорят про очередь отрисовки орнул в голосину

Ответить
0

Удалите это плиз: Но кроме визуального артефакта, который заметит игрок, это повлияет и на время рендера — ведь пиксели в этом месте будут постоянно «спорить» друг с другом об очереди отрисовки.

Ответить

Прямой эфир

[ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fizc" } } }, { "id": 4, "label": "Article Branding", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "cfovz", "p2": "glug" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "clmf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fjog" } } }, { "id": 10, "disable": true, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "disable": true, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "clmf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-250597-0", "render_to": "inpage_VI-250597-0-1134314964", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=clmf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Баннер в ленте на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudo", "p2": "ftjf" } } }, { "id": 16, "label": "Кнопка в шапке мобайл", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "chvjx", "p2": "ftwx" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fzvc" } } }, { "id": 20, "label": "Кнопка в сайдбаре", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "chfbl", "p2": "gnwc" } } } ]
{ "jsPath": "/static/build/dtf.ru/specials/DeliveryCheats/js/all.min.js?v=05.02.2020", "cssPath": "/static/build/dtf.ru/specials/DeliveryCheats/styles/all.min.css?v=05.02.2020", "fontsPath": "https://fonts.googleapis.com/css?family=Roboto+Mono:400,700,700i&subset=cyrillic" }