Garry's Mod

Garry's Mod

45 ratings
Hammer Editor: оптимизация уровней
By Satton(RU)
Оптимизация уровней (карт) в любом игровом движке является одним из наиболее важных аспектов, поскольку хорошо оптимизированная карта позволяет более плавно взаимодействовать с миром игры, например, наполняя его всё бо́льшим и бо́льшим количеством элементов без лишней нагрузки на игрока или для обеспечения повышенной доступности для игроков с более слабыми компьютерами, что и рассмотрим в руководстве.

Внимание: руководство нацелено на Hammer Editor для Garry's mod и может несколько не соответствовать тому же редактору для других игр, а также на пользователей, понимающих основную терминологию картодельства и его базовую работу.

Рекомендация: перед прочтением ознакомьтесь с двумя другими руководствами:
- «Познаём Hammer Editor: основы работы»
- «Hammer Editor: начальные ошибки и советы»
2
   
Award
Favorite
Favorited
Unfavorite
Введение: виды оптимизации и концепт
Допустим, что вы хотите оптимизировать свой уровень (карту), но не знаете как это сделать.

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

Какие виды оптимизации будут рассматриваться:
  • оптимизация производительности уровня — производительность (количество кадров в секунду) конечной карты (bsp);
  • оптимизация скорости компиляции;
  • оптимизация лимитов уровня — уменьшение / контроль использования лимитов;
  • оптимизация веса уровня — уменьшение / контроль веса конечной карты (.bsp).

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

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

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

При этом в конце руководства также будет предоставлен VMF-файл тестовой карты, которая будет использована в руководстве, для самостоятельной перепроверки на случай, если захотите протестировать всё сами. Это особенно полезно, если руководство будет долго не получать обновления и что-то устареет (об устаревании прошу уведомлять в комментариях руководства).
Раздел 1 — понимание видов оптимизации: часть 1
Ранее мы определили какие виды оптимизации будут рассмотрены в руководстве, а теперь рассмотрим каждый из них детальнее.

Оптимизация производительности уровня
Оптимизация производительности уровней в Source происходит весьма интересным образом.

Если многие современные игры работают по принципу «рендеринг зависит от камеры игрока» (то есть что видит, то и нагружает), то в Source принцип иной — «рендеринг зависит от области, в которой находится игрок». Таким образом не всегда то, что видит игрок, является причиной нагрузки, поскольку нагрузка может идти «за кадром».

Разберём на примере: два помещения, один общих проход, множество бочек.

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

В движке Source этот принцип не работает и действует принцип «рендеринг зависит от области, в которой находится игрок». Эти области в Source называются визуальными листами (сокращённо визлисты или английский visleaf).


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


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

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

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

У визлистов также есть грани соприкосновений с другими листам. Каждая такая грань называется порталом (в компиляции числится как numportals, визлисты — portalclusters при включённом этапе VVIS)

Для демонстрации факта рендеринга перейдём в игру и воспользуемся консольной переменой mat_wireframe 1 (требуется sv_cheats).

В итоге мы увидим прямое подтверждение того, что находясь в листе 1 нам рендерится всё содержимое листа 3 (и листа 2 соответственно).

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

Как создаются визуальные листы
Визлисты автоматически создаются, если уровень герметично закрыт, то есть не имеет утечек.

Их создание происходит от трёх элементов:
  • базовой геометрии уровня (обычных брашей);
  • автоматической разрезки каждые 1024 юнита;
  • части брашевых сущностей (принцип схож с обычными брашами).

Создание от базовой геометрии
Любой обычный браш в уровне будет вызывать разрезку листов (см. скриншот).

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

Благодаря этому всеми брашами в центре образовался ровный проход:
  • браш-прямоугольник образовал три листа, где два из них идут чётко по оси y, блокируя видимость между друг другом за счёт прямоугольника;
  • браш-полустолп — попытался сделать тоже самое;
  • браш-треугольник — образовал один лист, с учётом самого себя;
  • браш-округлый столп — хотел повторить успех предшественников, но из-за сложности формы это не получилось.

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

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

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


Чтобы просмотреть сформированные порталы в редакторе нужно нажать на «Map» → «Load Portal File». В трёхмерном окне будут показаны синие линии, демонстрирующие порталы. Отменить показ можно через опцию «Unload Portal File» в «Map».


Создание от автоматической разрезки
В любом двухмерном окне мы можем видеть автоматические линии разрезки, которые формируют собой кубы 1024x1024x1024 юнита, если смотреть как на трёхмерный объект.

Есть два цвета линий разрезки:
  • оранжевый — обычные линии кубов.
  • голубой — образуют крест, центр которого является исходной (нулевой) точкой уровня.

Грань такого куба (или же линии в двухмерном окне) нарезает листы независимо от наличия геометрии вблизи. Если такая линия проходит насквозь геометрии уровня, то это может привести к созданию лишних листов, поэтому крайне желательно размещать геометрию уровня таким образом, чтобы она либо находилась в пределах такого куба, либо не создавала лишних листов (подробнее см. руководство → раздел 7)

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

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

На скриншоте мы можем видеть трёхмерное окно с отображением порталов (линии синего цвета), двухмерное окно с видом сбоку, а также куб, который в теории сформировался бы, если бы происходила горизонтальная разрезка.



Как мы видим вертикально порталы доходят до самого потолка и никакой горизонтальной разрезки не происходит, хотя горизонтальные линии есть и формируют верхние и нижние грани куба.
Раздел 2 — понимание видов оптимизации: часть 2
Оптимизация скорости компиляции
Чтобы уровень был собран и мы получили конечный формат в виде файла .bsp, требуется время на эту самую сборку — компиляция.

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

Вкратце напомню, что есть три этапа компиляции:
  1. VBSP — структура уровня, работоспособность, создание визлистов, проверка утечек и пр.
  2. VVIS — обработка визлистов.
  3. VRAD — обработка освещения уровня.
Здесь важно понимать, что создание визлистов идёт на самом первом этапе. Для проверки и поиска излишек вам достаточно использовать только первый этап (VBSP), а остальное не требуется (пользуйтесь, чтобы сэкономить время, выключив лишние этапы).

Длительность каждого из этапов:
  1. VBSP — самый быстрый: обычно занимает не более минуты даже на очень сложных картах.
  2. VVIS — зависит от количества визлистов и порталов. Обычно занимает менее 15 минут, но на особо открытых картах или плохо оптимизированных может занимать несколько часов.
  3. VRAD — зависит от карт освещения (известные как лайтмапы или lightmap) и их размеров, параметров компиляции, детализации моделей и пр. Обычно занимает менее получаса, но может занимать несколько часов.
В обычных ситуациях зачастую VRAD будет занимать наибольшее количество времени, хотя возможны ситуации, где VVIS занимает значительно больше даже при хорошей оптимизации.

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

Оптимизация лимитов уровня
Лимиты, они же предел возможного количества элементов уровня, присутствуют и в Source.

Например, на момент написания руководства лимит брашей в Hammer для Garry's Mod составляет 65 535 шт. Достигнув его, компиляция будет невозможна — это называется «жёстким» лимитом.

Есть и «лёгкие» лимиты. К ним относятся преимущественно те элементы, у которых нет прямого количественного лимита (обычно представляют собой «[variable]» или «0/0» во втором столбце журнала компиляции), но есть лимит используемой памяти.

К ним можно отнести лимит entdata, у которого максимальное значение памяти 393 216 байт (384 Кбайт), хотя в большинстве случаев его превышение не приведёт к остановке компиляции, но может вызвать дополнительную нагрузку между сервером и клиентом.

Актуальную информацию по лимитам вы можете посмотреть, скомпилировав любой уровень с включённым этапами VBSP и VRAD (пример информации по лимитам на скриншоте), если используется параметр «verbose».


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

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

Если, например, использовать множество «дорогих» сущностей (о них позднее) или использовать 10 брашей вместо одного, то вес уровня будет значительно увеличиваться.

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

NoDraw и её влияние на оптимизацию
Служебная текстура NoDraw используется на тех сторонах брашей, где игрок не способен её видеть. В игре текстура NoDraw не отображается, то есть её частично можно назвать «невидимой».

Особенности
  • имеет коллизию (не пропускает сквозь себя игроков, неигровых персонажей, объекты, снаряды, пули);
  • блокирует видимость для НИПов;
  • блокирует видимость для игрока, если визлист позади грани не является видимым визлистом, в котором находится игрок, и является «прозрачной» в иных случаях;
  • грани, покрытые текстурой, не оказывают нагрузку на производительность;
  • грани, покрытые текстурой, не задействуют их лимит (faces);
  • грани, покрытые текстурой, меньше влияют на вес уровня;
  • режет визуальные листы и герметизирует уровень;
  • не отрисовывает на себе тени;
  • отбрасывает тени.

Для детального рассмотрения влияния на нагрузку и лимиты возьмём уровень и заполним его 168 кубами размером 64 юнита каждый, а после сделаем три замера:
  • уровень без кубов;
  • уровень с кубами в текстуре NoDraw;
  • уровень с кубами в любой неслужебной текстуре.


Влияние на оптимизацию
Замер
Лимит граней (faces)
Кадров/с (среднее)
Вес уровня (в КБ)
Без кубов
26
1 250
93
NoDraw
26
1 250
244
Текстура
1 034
1 165
813

Между первым и вторым замером отличий в лимитах и производительности нет, чего не скажешь о третьем, где разница составила ≈ 6,8% по количеству кадров, ≈ 70% по весу уровня (в сравнении с NoDraw) и значительно повлияла на количество граней в лимитах.

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


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


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

Построение брашей и их влияние на оптимизацию
Сперва поймём, что такое лимит брашей (brushes) граней (faces) и брашевых сторон (brushsides).

Браши — лимит, расходующийся при создании браша любой формы (параллелепипед, столп, шар и пр) и не зависит от привязки к брашевой сущности (то есть даже после привязки будет учитываться в лимитах брашей, помимо лимита сущностей).

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

Брашевые стороны — отдельный лимит, который в корне отличается от граней и зависит не только от них, но и от ограничивающего параллелепипеда (он же Bounding box или BBox). На него не влияют текстуры, наподобие NoDraw. Не зависит от привязки к брашевым сущностям.

Вкратце, у каждого объекта в Source есть ограничивающий параллелепипед, который всегда находится в одном положении (соответствует направлениям сетки), невидим и неосязаем для игрока. Он нужен для определения технических границ объекта и всегда имеет 6 граней (две боковых, передняя, задняя, верхняя и нижняя).

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


Не путаем грани брашей и параллелепипеда: у параллелепипеда грани не учитываются лимитом граней уровня.


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

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

Для наглядности рассмотрим ещё 4 примера:
  1. 7 сторон — 5 от браша и 2 от параллелепипеда (бок и перед);
  2. 7 сторон — 7 от браша и 0 от параллелепипеда;
  3. 8 сторон — 6 от браша и 2 от параллелепипеда (верх и низ);
  4. 6 сторон — 6 от браша и 0 от параллелепипеда.

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

Арки

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

Тротуарные повороты и полустолпы (первые 2 созданы формой «арка», а другие — «цилиндр»)

Более наглядный разбор полустолпов и поворотов: см. руководство → раздел 4.

Влияние на время компиляции, производительность и вес не замечено (не считая случаи, где больше брашей и видимых граней).
Раздел 4 — базовое: func_detail и лимит waterindices
Есть несколько основных элементов, используемых в оптимизации, и каждый из них оказывает разное влияние на разные её виды. В этом разделе рассмотрим func_detail.

func_detail
На скриншоте для примера два браша слева привязаны к сущности func_detail.
func_detail — основная сущность, используемая для оптимизации количества визуальных листов и их порталов. При применении сущности к брашу (или нескольким), ему присваивается свойство, которое лишает его возможности блокировать рендер, а следовательно резать листы и герметизировать карту от утечек.

Важно: порой сквозь func_detail может просачиваться свет, если размер карт освещения отличается.

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

func_detail влияет на лимиты по waterindices, которые появляются от соприкосновения обычных брашей с func_detail (если соприкосновения не будет, лимит не изменится; реже от соприкосновения с собой), что может привести к ошибке «Too many t-junctions to fix up!» и невозможности компиляции.

Полезное: большинство брашевых сущностей не влияют на лимит waterindices.

Обычно используется в следующих случаях (не ограничивается ими):
  • брашевые перила и заборы;
  • небольшие здания;
  • ступеньки;
  • выпирающие части зданий;
  • повёрнутые браши;
  • столпы и полустолпы.

Про ступеньки поговорим подробнее, поскольку насчёт них есть давно закреплённая практика оптимизации, которая редко разбирается по деталям и может восприниматься ошибочно, а также сможем понять концепт лимита waterindices лучше.
Разберём три разных подхода, изображённых на скриншоте:
  1. превращение верхней части ступенек в «треугольники», а нижнюю — в общий для всех;
  2. создание каждой ступеньки и растягивание её до самого низа;
  3. создание каждой ступеньки без растягивания.
Примечание: каждая невидимая игроку грань окрашена в текстуру NoDraw.

Что верно для указанных видов в большинстве ситуаций (номер = номер вида):
  1. экономия количества граней, больше затрата брашевых сторон и брашей;
  2. обычная затрата брашевых сторон, граней и брашей;
  3. обычная затрата брашевых сторон, граней и брашей.
Влияние на оптимизацию

Примечание: все виды плотно приставлены к одному брашу-стене, тесты делались отдельно для каждого вида (другие виды скрывались), в func_detail обращались только сами ступеньки (стены и нижний треугольник у первого вида не менялись, кроме четвёртого столбца).
Вид
До func_detail
После func_detail
+ func_detail для нижнего треугольника
Первый
brushes 21
brushsides 139
faces 117
waterindices 63
21
139
92
108
21
139
88
48
Второй
brushes 20
brushsides 120
faces 120
waterindices 108
20
120
86
39
Третий
brushes 20
brushsides 120
faces 117
waterindices 63
20
120

88
78
Примечание: подчёркнуты наименьшие значения.

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

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

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

Ещё одним аргументом в пользу первого вида выступает теоретически более верное строение визлистов, поскольку они диагонально подстраиваются формой под нижний треугольник (если он не func_detail). Это действительно верно, но нужность такого визлиста варьируется от случая к случаю и практическая польза между подстроившимся и не подстроившимся может отсутствовать, поэтому является сомнительным.

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

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

При сшивании могут как образовываться дополнительные грани, так и отсеиваться лишние, тоже самое касается и waterindices, который представляет собой эти сшивания. Сшивание func_detail между собой входит в лимит waterindices, но реже.

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

Теперь рассмотрим ситуацию, когда нижняя и задняя грани видны (примечания те же):
Вид
До func_detail
После func_detail
+ func_detail для нижнего треугольника
Первый
brushes 21
brushsides 142
faces 113
waterindices 276
21
142
110
225
21
142
110
99
*
Второй
brushes 20
brushsides 130
faces 119
waterindices 222
20
130
*
113
114
Третий
brushes 20
brushsides 120
faces 135
waterindices 81
20
120

127
72
*на практике третий вид вряд ли будет использоваться из-за стилистических или архитектурных соображений, поэтому сравнение минимумов первого и второго выделены звёздочкой.

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

В иных ситуациях использование func_detail и его оценка будет происходить примерно теми же принципами и будет варьироваться от случая к случаю.
Раздел 5 — базовое: func_lod
func_lod
Брашевая сущность, которая исчезает на расстоянии согласно двум параметрам:
  • начальная дальность исчезновения (Disappear Distance Start) — указывает расстояние в юнитах, на котором начнётся процесс исчезновения (по умолчанию 2 000).
  • конечная дальность исчезновения (Disappear Distance End) — указывает расстояние в юнитах, на котором исчезновение произойдёт полностью (по умолчанию 2 800).

Примечание: не всегда исчезновение происходит плавно и объект может резко пропасть на конечной дальности.


Как и большинство брашевых сущностей, не режет листы, не отбрасывает тени и не влияет на лимит waterindices.

По умолчанию перемещаема физпушкой или доступна для воздействия каким-либо инструментом, если не установить ограничения в параметрах «Allow Physics Gun» (разрешить физическую пушку) и «Sandbox Tool Whitelist» (белый список инструментов).


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

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

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

Повторим эксперимент с кубами из раздела 3.
Каждый куб привязан к сущности, а все func_lod рендерятся:
Замер
Браши
func_detail
func_lod
func_brush
Лимиты
models 1
planes 108
nodes 396*
texinfos 10
leaves 398*
leaffaces 1 222
visdata [variable] 14 276
entdata [variable] 345
LDR ambient table 398*
HDR ambient table 398*
LDR leaf ambient 223*
HDR leaf ambient 398*
physics [variable] 69 443
1
108
6
10
8
1 034
[] 14
[] 345
8
8
1
8
[] 69 443
169
116
1 014
10
1 184
1 034
[] 14
[] 20 397
1 184
1 184
1 009
1 184
[] 95 976
169
128
1 014
108
1 184
1 034
[] 14
[] 67 941
1 184
1 184
1 009
1 184
[] 95 976
Кадров/с ≈
Вес
1 300
813* КБ
1 300
755
КБ
1 220
948 КБ
1 160
1 001 КБ
Примечание: звёздочкой отмечены наилучшие значения без учёта func_detail, только если наилучший не является одинаковым с ним.

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

При этом, по лимитам, весу и производительности func_lod выигрывает у func_brush поэтому лучше использовать именно func_lod как замену func_detail, нежели более дорогую сущность. По производительности, разумеется, результат будет ещё лучше после исчезновения на расстоянии.
Раздел 6 — базовое: деформации и модели
Деформации (они же дисплейсменты или displacements)
Используются для формирования различного ландшафта: холмов, ям, бугров, гор и схожего.

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

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

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


О создании деформаций прочтите информацию из официальной вики или других источников.


Особенности
  • есть 3 уровня деформаций, именуемые «мощностью» (power): 2, 3 и 4. Чем больше мощность, тем детальнее и визуально плавнее может быть деформация, но тем выше и нагрузка, поэтому рекомендуется разбивать деформации на несколько более «слабых».
    Примечание: в других играх Source мощность 4 может приводить к вылетам игры, а в Garry's Mod — сильную нагрузку при столкновении с физическими объектами. Также она тратит примерно на 92% больше лимит physics, чем другие (2 и 3 почти не имеют различий в этом лимите между собой);
  • может быть беспрепятственно деформирована для её прохождения сквозь браши;
  • не может быть привязана к какой-либо сущности (возникнет ошибка);
  • не режет визуальные листы.

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

Есть три основных вида сущностей с моделями:
  • prop_physics — физическая перемещаемая модель. Имеет аналог в виде prop_physics_multiplayer, который более оптимизирован под серверы, но в остальном идентичен.
  • prop_static — статичная неперемещаемая модель, с которой почти нельзя дополнительно взаимодействовать.
  • prop_dynamic — модель, поддерживающая анимирование и которая не может быть перемещена игроком обычными способами (преимущественно перемещается посредством триггеров или других элементов).

Основные моменты при сравнении
  • prop_static — самый дешёвый вид за счёт отсутствия отбрасывания динамичных теней (тени заранее запечены в карту) анимаций и физики движения, а также отсутствия как сущности на готовой карте (не будет учитываться лимитами сущностей движка);
  • prop_physics_multiplayer рекомендуется использовать в случаях, когда карта подразумевает игру по сети, поскольку просчёт движения модели происходит в упрощённом формате и со стороны сервера, что обеспечивает более точную синхронизацию движения, но порой менее реалистичное движение;
  • небрашевые модели (те, что уже есть в Source и созданы через программы для моделирования) в плане оптимизации разбираются уже уровне моделирования: картоделам разве что важно грамотно их расставлять — с чувством меры и планированием дальнейшей оптимизации;
  • браши тоже нередко обращаются в модели для оптимизации (брашевые модели), когда это уместно (об этом ниже).


О создании модели из брашей прочтите информацию из официальной вики или других источников.

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


У всех перечисленных сущностей есть свойство, позволяющее оптимизировать производительность — исчезновение на расстоянии. Обычно, регулируется двумя параметрами:
  • начальная дальность исчезновения (Start Fade Dist) — указывает расстояние в юнитах, на котором начнётся процесс исчезновения (по умолчанию -1).
  • конечная дальность исчезновения (End Fade Dist) — указывает расстояние в юнитах, на котором исчезновение произойдёт полностью (по умолчанию 0). Если не указать начальную дальность, модель исчезнет мгновенно после перехода за пределы этого значения, если это prop_static (у других сущностей: только если < 500 юнитов, а если иное — от конечной отнимается 400 юнитов)

Об ограничении дальности
  • производительность в процессе перехода будет ниже, чем если объект полностью будет показан (примерно на 5%), поскольку идёт расчёт уровня прозрачности от расстояния, поэтому не делайте большую разницу между значениями дальности (рекомендуется держать разницу в пределах 50 юнитов и менее);
  • полностью исчезнувшая модель не теряет физических свойств и статичную тень;
  • полностью исчезнувшая модель перестаёт оказывать нагрузку на производительность;
  • рекомендуется использовать на небольших и малозаметных элементах.

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

Сравнивать будем три элемента: func_detail, деформации и брашевые модели.

Формат теста будет схожим с разделом 5, но вместо кубов создадим простой дверной проём, состоящий из четырёх брашей и другими особенностями:
  • в тесте 210 проёмов;
  • деформации: обращены только видимые грани, используя минимальную мощность — 2;
  • модели: использована сущность prop_static;
  • func_detail и модели: вершины смещены для сокрытия лишних граней, а невидимые грани окрашены в NoDraw;
  • поскольку мы уже знаем, что func_detail влияет на лимит waterindices, а остальные элементы — нет, то приподнимем проём, чтобы он не соприкасался с обычными брашами и мы получили более чистый результат. Тоже касается лимитов брашей и брашевых сторон;
  • в модели использовались входящие в игру текстуры, поэтому дополнительного веса от них не будет;
  • в тесте будет базовое освещение от солнца.

Замер
func_detail
Модель
Деформация
Лимиты
planes 346
vertexes 3 397
texinfos 23
faces 3 386
origfaces 3 370
surfedges 27 040
edges 13 521
LDR lightdata [variable] 269 844
physics [variable] 328 835
physics terrain [variable] 2
38
37
7
26
10
160
81
[] 58 884
[] 3 576
[] 2
342
3 397
35
3 386
3 370
27 040
13 521
[ ] 263 060
[ ] 3 576
[ ] 178 082
Кадров/с ≈
Вес
VRAD, сек.
1 350
1 300 КБ
3
1 140
118 КБ (с учётом файлов модели)
1
1 090
3 695 КБ
5

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

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

По производительности выигрывает func_detail.

Если нужно сэкономить лимиты и вес, ландшафт деформировать не нужно, то лучше выбирать модели. При деформировании — деформации, а в остальных случаях — func_detail.
Раздел 7 — базовое: оптимальное размещение скайбокса
Оптимальное размещение скайбокса (брашей с текстурой неба — toolsskybox или toolsskybox2d) относится не только к соблюдению герметичности уровня и избеганию утечек (разбиралось в этом руководстве → раздел 5), но и оптимизации, о чём поговорим подробнее.

Возьмём простой уровень среднего размера без подробной детализации относительно открытого типа.


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

Примечание: для улучшения видимости деталей на скриншоте в третьем варианте часть граней скайбокса заменена на текстуру Skip (при компиляции всё ещё использовалась текстура скайбокса), а скайбокс в третьем способе расставлен только там, где не подразумевается никакого взаимодействия.
Разберём плюсы и минусы:
  1. самый быстрый способ, но создаёт множество лишних визлистов и игрового пространства, которое позднее придётся закрывать;
  2. более долгий способ, но создаёт гораздо меньше визлистов и исключает большинство лишнего игрового пространства;
  3. самый долгий способ, но создаёт минимум визлистов, почти полностью исключает лишнее игровое пространство, способствует дальнейшей оптимизации, блокируя видимость между визлистами (примечание: если уровень подразумевает попадание на крыши или переброс через них объектов, то скайбокс над крышами не позволит игроку и объектам пройти через него).
Цифры:
Замер
Способ 1
Способ 2
Способ 3
Визлисты
Визпорталы
167
394
70
148
62
119
Примечание: поскольку уровень очень мал и прост, то расчёта длительности компиляции не было (в моём случае все способы заняли не более секунды).

Напоминание: чем меньше визлистов, тем быстрее просчёт VVIS и быстрее компиляция, а также меньше вес.

Способ 3 оказывается самым эффективным из всех, а способ 1 — самым неэффективным со стороны скорости компиляции и веса.

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

С помощью способа 2 и особенно 3 мы исключаем «случайное» виденье одного листа другим, например, за счёт высоты. Посмотрим на сравнение способов 1 и 3 в плане рендера в разных локациях:
Количество рендера геометрии и других элементов значительно уменьшилось в способе 3 за счёт перекрытия видимости для визлистов.

Это крайне положительный результат, поскольку мы ещё не переходили к каким-либо дополнительным способам оптимизации производительности, но движок и редактор уже выполнили отличную работу по оптимизации за счёт нашего оптимального размещения скайбокса.
Раздел 8 — продвинутое: func_viscluster
func_viscluster — брашевая сущность, способная объединить несколько визлистов в один общий. Не имеет строгих ограничений по используемой текстуре, но рекомендуется использовать с tools\toolstrigger, а также не имеет дополнительных настроек.

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

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

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

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

Разбираем концепт детальнее
Ниже можем видеть два визлиста и рендер из них.


Если мы их объединим их с помощью func_viscluster, рендер у них будет общим.

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

Также есть ряд ограничений при объединении визлистов
  • для надводных и подводных визлистов нужно делать отдельные сущности (то есть нельзя объединить визлисты, если одни находятся под водой, а другие — на поверхности);
  • нельзя ставить сквозь ареапорталы.
Обычно используется в следующих случаях (не ограничивается ими)
  • объединение визлистов в небе (осторожно, чтобы случайно не зацепить наземные визлисты или те, которые тянуться от неба до самой поверхности, что может повлиять на производительность);
  • скопление визлистов, которые не оказывают влияния (или оказывают незначительно) на производительность, но которые не удалось убрать другими путями.
Влияние на оптимизацию
  • производительность: варьируется, но при правильном использовании, не оказывает негативного влияния.
  • скорость компиляции: варьируется, но преимущество оказывает положительное влияние (особенно если уровень открытого или околооткрытого типа, где скорость может измениться с нескольких часов, до нескольких десятков минут)
  • вес: не влияет, поскольку количество визлистов не меняется.
  • лимиты: затрагивает брашевые лимиты компиляции, но после неё удаляется и не влияет на лимиты готового уровня.
Раздел 9 — продвинутое: карты освещения (лайтмапы, lightmap)
Карты освещения — это сгенерированная текстура, которая позволяет эмитировать освещение. Чем точнее карты освещения (лучше качество освещения; меньше её разрешение), тем больше нагрузка на компиляцию (в частности на этапе VRAD), вес карты и лимиты.

Чтобы наглядно увидеть карты освещения, нам нужно переключится на 3D-вид с отображением сетки карт освещения (3D Lightmap Grid), после чего мы начнём видеть карты освещения (по умолчанию в белом цвете с синими границами).



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


Для наглядности посмотрим, какое будет качество теней, если установить разрешение на 1 (красным), 16 (белым) и 32 (голубым).



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


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

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


При этом карты освещений могут быть не только этих разрешений, но рекомендуется придерживаться тех, что кратны двум (как и разметочная сетка редактора), то есть 1, 2, 4, 8, 16 и так далее (желательно не выше 128, чтобы избежать сильных визуальных неточностей). Это связано с тем, что неполностью совпадающие с гранью люксели могут иметь «кривое» освещение.

Кроме того, разные разрешения имеют разные цвета:


Влияние на оптимизацию
Сравним влияние при разрешении 1, 16 и 32, где возьмём простую локацию с 450-ю бетонными плитами, у которых будет меняться разрешение.


Примечание: браши привязаны к func_detail, а нижняя грань окрашена в NoDraw, поэтому влияния не оказывает.


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

Замер
Разрешение «1»
Разрешение «16»
Разрешение «32»
Лимиты
vertexes 21 940
faces 17 274
leaffaces 17 518
surfedges 78 924
edges 44 419
LDR lightdata [variable] 39 591 784
3 820
2 424
2 548
19 014
11 314

[] 571 384
3 820
2 424
2 548
19 014
11 314
[] 399 784
Кадров/с ≈
Вес
VRAD, сек.
885
39,9 МБ
72
1 300
1,23 МБ
2
1 320
1,06 МБ
1

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

Чтобы убедиться в этом, проведём такой же тест, но с 90 более длинными брашами.




Замер
Разрешение «1»
Разрешение «16»
Разрешение «32»
Лимиты
vertexes 19 660
faces 16 554
leaffaces 16 554
surfedges 68 604
edges 37 459
LDR lightdata [variable] 48 032 344
1 300
894
952
5 694
3 304
[] 565 264
940
624
676
4 614
2 674
[] 373 744
Кадров/с ≈
Вес
VRAD, сек.
910
47,6 МБ
58
1 350
775 КБ
1
1 385
560 КБ
1

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

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



Качество «теней» относится не только к тем, что формируются от объектов
Источники света также формируют своего рода «тени»: на примере выше свет пробивается сквозь кромешную тьму и граница между светом и тьмой тоже зависит от разрешения карт освещения, поэтому ближайшие браши к этой границе остались в разрешении 16, чтобы сильно не повлиять на визуальную часть.

Большое разрешение обычно используется в следующих случаях (не ограничивается ими)
  • любые грани, на которые не падают статичные тени (в том числе те, что находятся в кромешной тьме);
  • любые грани, на которые падают статичные тени, но не требуется чётких теней от объектов (нередко крыши или стены зданий, уличные площади, неосвещённые стены/полы/потолки и подобное).
Раздел 10 — продвинутое: хинты (служебная текстура Hint)
Служебная текстура Hint (tools/toolshint; далее «хинт») — текстура, позволяющая указать редактору (а вернее «подсказать», о чём позже), где нужно провести разрез визуальных листов, но не добавляя в уровень новых видимых элементов (скрытно провести разрез).

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

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

Грани, которые нам не нужно использовать как «лезвие», мы покрываем другой служебной текстурой — Skip (tools/toolsskip). Она не взаимодействует с уровнем или редактором и удаляется после компиляции. Рекомендуется сперва создавать браши с этой текстурой, а после накладывать текстуру Hint.


Несмотря на то, что хинты и текстура Skip не присутствуют в готовом уровне, они всё ещё влияют на брашевые лимиты при компиляции, такие как: brushes, brushsides, planes и ряд других. При этом на лимиты граней (faces) и вершин (vertexes) они не влияют.


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

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

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

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

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

Если это будет уместно и возможно (как в нашем случае), редактор пересмотрит создание визлистов и сменит их форму, нежели добавит новые.

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


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



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

При просмотре 2D-вида сбоку мы видим, что нам достаточно повторить первый хинт из прошлого примера, чтобы этого избежать, но в другой плоскости.







Применение — комбинирование
Рассмотрим более сложную задачу, где нужны как горизонтальный, так и вертикальный хинты.

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

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

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

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

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



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

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

Кроме того, хинты имеют свойство «дотягиваться» до ближайшей «опоры» (браша, линии автоматической разрезки) самостоятельно, если не были дотянуты до них в редакторе.
Раздел 11 — продвинутое: ареапорталы (func_areaportal)
Ареапортал (портал области) — это брашевая сущность, обычно покрытая со всех граней текстурой tools\toolsareaportal. Позволяет ограничить рендрер в той области, которую герметизирует, скрывая тот рендер, который не проходить сквозь ареапортал.

Есть два вида:
  • func_areaportal — стандартная версия, которую можно «закрыть» или «открыть» с помощью триггера или связанной двери;
  • func_areaportalwindow — аналог, способный «закрываться» и «открываться» в зависимости от расстояния игрока до сущности и оставлять на своём месте другой браш.

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

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

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

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

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

func_areaportalwindow и «закрытие» от расстояния
У этой сущности за расстояние отвечает два параметра:
  • Fade Start Distance (начальное расстояние исчезновения) — то, когда ареапортал начинает закрываться.
  • Fade End Distance (конечное расстояние исчезновения) — то, когда ареапортал полностью закрывается.
Оба параметра указываются в юнитах.

Обычно к ним используются ещё два параметра:
  • Rendered Window (окно для рендера) — окном выступает брашевая сущность (зачастую func_brush), имя которой указывается в этот параметр. Когда ареапортал закрывается, на его место встаёт указанная сущность, которая нередко окрашена в тёмные текстуры и находится прямо в ареапортале.
  • Translucency limit (предел прозрачности) — максимальная прозрачность окна для рендера. По умолчанию «0.2», что приводит к малозаметной видимости окна даже в открытом состоянии, поэтому рекомендуется ставить на «0».

func_areaportal и привязка к двери
Привязка может происходить и к дверям (обычно prop_door_rotating / func_door).

В свойствах ареапортала нужно будет указать название двери в параметре «Name of Linked Door». Если дверь изначально закрыта, то параметр изначального состояния (Initial State) нужно будет установить на «Закрыто».

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




Особенности использования ареапорталов
Максимальное количество в уровне: 191.
Явной ошибки компиляции может не быть, но при попытке загрузить карту будет ошибка, что приведёт к вылету игры. Также влияют на ряд брашевых лимитов.

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

На скриншоте у ближнего ареапортала лишние листы, а у дальнего — нет.

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

На скриншоте видно, что в редакторе установлено три ареапортала для одной локации, но в игре они объединились в один общий, который и ограничивает рендер.

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

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

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

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

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

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

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

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

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

Вертикальность, горизонтальность и размер ареапортала неважны
Ареапорталы можно ставить как в стены, так и в пол, потолок или наклонные поверхности.

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

Ареапорталы нельзя ставить сквозь воду
Если появилась потребность сделать ареапортал под и над водой, потребуется воспользоваться двумя разными ареапорталами: один над ней, второй — под.

Если использовать один общий, произойдёт ошибка или утечка.

Обычно используется в следующих случаях (не ограничивается ими)
  • строения, с небольшим количеством входов и выходов;
  • длинные проходы, соединяющие одну локацию с другой;
  • разделение большого уровня на этапы, где зачастую крупный ареапортал закрывается по окончанию одной из них;
  • в уличной части уровней, где нужно разделить менее крупные локации (дворы, подворотни, входы в метро и пр.) от локаций покрупнее (центральные площади, шоссе, главные дороги, парки и пр.).
Раздел 12 — продвинутое: окклюдеры (func_occluder)
Окклюдер (func_occluder) — это брашевая сущность, покрытая текстурой tools\toolsoccluder на рабочих гранях и текстурой NoDraw на нерабочих. Позволяет скрывать рендер моделей любого вида, которые покрываются рабочей гранью.

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

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

По умолчанию окклюдер активен. За активность отвечает параметр «Initial State» (изначальное состояние), который можно сменить на неактивное (Inactive) на момент создания или воспользовавшись триггерами.

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

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

При этом если окклюдер находится в нескольких локациях, то может высветиться предупреждение «Occluder "" straddles multiple areas. This is invalid!». Если это было сделано намеренно, то можно не обращать внимания.


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

Окклюдеры имеют некоторое ограничение по дальности работы
«Некоторое» оно от того, что не удаётся выявить чёткую закономерность в максимальной дальности. В среднем небольшие по размеру окклюдеры выключаются на расстоянии 512 – 1 024 юнитов (большие ≈ 1 024 – 2 048 юнитов). Чем они больше, тем обычно дальше они работают.

Также окклюдеры разных размеров могут выключаться раньше или работать дальше в зависимости от того:
  • как вы на них смотрите (под каким углом);
  • насколько они полезны: могут ли они скрыть хоть какой-то объект (если не могут, дальность может значительно снизиться);
  • не делает ли их работу соседний окклюдер (если один окклюдер скрывает большинство элементов другого, второй может выключиться раньше);
  • насколько сильно видим окклюдер (если бо́льшая его часть невидна, он может выключиться из-за ненадобности)

Обычно используется в следующих случаях (не ограничивается ими)
  • большие непрозрачные заборы или ограждения;
  • крупные недвижущиеся модели (грузовые контейнеры, валуны, скалы, большие мусорные контейнеры, непрозрачные заборы и подобное);
  • стены сквозных зданий (то есть тех, в которых много щелей/окон/дверных проёмов и где невыгодно использовать ареапорталы, но часть стен могут быть использованы под окклюдеры для скрытия моделей)
Раздел 13 — завершающее: тестирование
В руководстве мы проверяли, подтверждали и тестировали разные подходы к оптимизации и их влияние, но важно уметь делать это самостоятельно, поскольку на практике может быть множество неоднозначностей.

Сравнение веса
Сохраняем прошлую версию карты и сравниваем с новой.

Важные моменты (для чистоты результата)
  • настройки компиляции должны быть полностью идентичны между версиями;
  • не вшиваем и не прибавляем дополнительный контент карты на этом этапе (сравниваем вес самой карты, а не дополнительного контента — его сравниваем отдельно);
  • проверяем, чтобы в обеих версиях не было утечек или иных проблем/ошибок.

Сравнение лимитов и скорости компиляции
  1. чистим журнал компиляции (удаляем/переносим из папки компиляции/чистим содержимое файла);
  2. компилируем одну версию карты и переносим куда-либо для сравнения (при желании подписываем);
  3. повторяем процедуру со второй версией карты;
  4. открываем оба журнала и самостоятельно сравниваем нужные значения либо можем воспользоваться каким-нибудь сайтом для сравнения текстов.
Это позволяет избежать путаницы среди множества текста журналов компиляции и сохранить историю разных версий на будущее.

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

Сравнение производительности
Перед сравнением (для чистоты результата)
  • выключаем все работы из Мастерской;
  • выключаем все лишние запущенные приложения;
  • не посещаем какой-либо сервер/не запускаем другую карту или версию (запускаем игру с нуля);
  • (если есть) сниманием ограничение по количеству кадров во внешних программах и игре (fps_max 0);
  • оставляем уровень в изначальном состоянии (ничего не трогаем и не добавляем);
  • (желательно) тестируем в небольшом интервале между друг другом (полчаса-час), поскольку ряд процессов может быть запущен компьютером незаметно и постепенно повышать нагрузку;
  • включаем «sv_cheats» (нужен для большинства команд);
  • используем отображение кадров из оверлея Steam или другим малонагружающим способом (в нём отображается усреднённое значение раз в пару секунд, а, например, «net_graph» снижает производительность и слишком быстро обновляет значения).
Если у вас мощный компьютер, не забывайте об игроках с более слабыми и сформируйте примерное понимание при каком значении кадров на вашем мощном компьютере у игроков с слабыми будет менее 75-100 кадров/с (с запасом, поскольку могут вносится изменения игроками / сервером).

Сравнение «статичных» моментов
Под этим подразумевается взятие конкретного места и его сравнение в разных версиях.
  1. переходим в желаемое место в первой версии карты;
  2. записываем среднее значение кадров в секунду или делаем скриншот с этим значением;
  3. не двигая мышью и не перемещаясь, вводим консольную команду «getpos» и копируем результат из консоли. Он выделен красным и выглядит примерно как «setpos 0 0 0;setang 0 0 0» (при желании можно записать где-нибудь возле значений кадров);
  4. в новой версии карты вводим скопированный результат в консоль: нас переместит в тоже место и с тем же положением камеры, где мы были при первом тесте (слегка выше, от чего мы упадём до нужного места);
  5. записываем среднее значение кадров в секунду или делаем скриншот с этим значением;
  6. сравниваем два результата.


При использовании скопированной команды вас может не переместить в указанное место, сославшись на перемещение внутрь какого-либо объекта (сообщение: setpos into world, use noclip to unstick yourself!). Варианты выхода из ситуации:
  • использовать режим полёта (noclip), но тогда вы будете выше нужной точки;
  • уменьшить третье значение в «setpos», отняв порядка 60 юнитов («setpos 0 0 0») и тогда мы появимся значительно ближе к желаемой точке.


Сравнение среднего количество кадров во всём уровне
Здесь идёт сравнение среднего значения кадров со множества локаций карты за раз через повтор и вывод в усреднённом итоговом варианте. Это полезно, когда отдельные моменты вы уже протестировали, но хотелось бы понять, какое среднее значение при хождении по уровню.
  1. придумываем маршрут по карте из точки «А» в точку «Б»;
  2. вводим консольную команду «record <названиефайла1>» на одной из версий карты;
  3. проходим по придуманному маршруту;
  4. вводим команду «stop»;
  5. вводим команду «timedemo <названиефайла1>» и дожидаемся окончания;
  6. записываем результат куда-либо (итог-пример: 0 frames 0.0 seconds 0 fps ( 0 ms/f) 0 fps variability);
  7. повторяем процесс с другой версией карты (можно использовать тот же файл для запуска проверки);
  8. сравниваем результаты.
При сравнении нас будет интересовать часть «0 fps | 0 fps variability», где первое — среднее количество кадров в секунду за весь повтор, а второе — насколько большой бывала разница от этого значения (например, если среднее — 900, а минимальное/максимальное — 600, то разница — 300).


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

Проверка видимости между визлистами
mat_wireframe
Ранее мы уже говорили о ней: позволяет видеть каркасную сетку моделей, брашей и прочего. Обычно для проверки оптимизации используется со значением «1» или «3» (значение 2 нежелательно, поскольку неполностью позволяет видеть сетку брашей, которые рендерятся, но позволяет получить более ясную картинку)

Цвета сетки разных элементов
  • Браши — розовые (зелёные при значении «2»);
  • Модели — голубые;
  • Спрайты — зелёные;
  • Деформации — белые;
  • Декали и оверлеи — жёлтые.

mat_leafvis
Отображает визуальные листы в игре в виде красной каркасной сетки.
Имеет несколько режимов:
  • 1 — отображает визлист, в котором вы находитесь;
  • 2 — отображает визкластер (группу визлистов). в котором вы находитесь;
  • 3 — отображает все визлисты, которые вы можете увидеть из текущего.

r_lockpvs
Позволяет увидеть рендер «от лица визлиста», в котором он был зафиксирован сменой значения команды на «1».

То есть, если установить значение на «1», находясь в каком-либо визлисте и перейдя в какое-либо другое место, те части уровня, которые визлист не видит, не будут рендериться. Для отмены фиксирования возвращаем значение «0».

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

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

Проверка видимости сквозь окклюдеры
r_visocclusion
При включении (значение «1») позволяет видеть рабочие грани окклюдеров (белым цветом) и ограничивающий параллелепипед скрываемых им моделей (скрытые — зелёным, нескрытые — красным).


Большинство способов могут хорошо сочетаться, а также снижать производительность!
Раздел 14 — завершающее: примеры — часть 1
Рассмотрев всё по отдельности остаётся два вопроса:
  1. Как это всё применить вместе на практике?
  2. Что лучше выбрать в тех или иных ситуациях?

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

Сама карта

Как видим, здесь есть над чем поработать.

Для истории обозначу ряд моментов на текущем этапе, которые мы будем отслеживать (часть будет обновляться на скриншотах):
  • Визлистов: 197
  • Визпорталов: 554
  • Среднее количество кадров за всю карту по маршруту: 1 189 (макс. разница: 394).
  • Вес карты: 1,06 МБ.
  • Лимиты будут подсчитаны в конце.
  • Какие способы применены сразу и рассмотрены не будут: NoDraw, базовая оптимизация строения брашей, оптимальное размещение скайбокса.

Работа с func_detail
Примечание: выделенные объекты привязываются к func_detail.

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


+ здесь мы подготавливаемся к ареапорталу.

Заметьте, что в глубине здания 2 стены, которые не были привязаны к func_detail. Конкретно в этом случае нужно было изолировать видимость ящиков друг от друга и для бо́льшей блокировки видимости со вторым этажом, поэтому они были оставлены:
в иной ситуации их можно было бы привязать к func_detail + здесь мы подготавливаемся к ареапорталу.



Здесь применялся func_lod: основной целью было не сокращение визлистов и порталов, а подготовка к ареапорталу и использование визуальной особенности брашевых сущностей (кроме func_detail, их грани видны сквозь NoDraw и скайбокс, даже если они стоят к ним вплотную):


Этого будет достаточно по работе с func_detail, поскольку мы сократили количество листов на 116 (57%), а порталов — 399 (72%), а также местами улучшили их построение.

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


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

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

Значение рекомендуется округлять в бо́льшую сторону (юнитов на 20-100), чтобы избежать случайных несвоевременных пропаданий (на скриншотах это уже сделано).

Примечание: выделенные объекты ограничиваются в дальности отображения.

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


Примечание: сравнивать можно было и ранее, но если вспомнить разделы про func_detail, карты освещения и скрывающиеся модели, то либо они не влияют на производительность (не считая возможных неправильных сокрытий через func_detail, коих здесь не было) либо влияют на неё положительно — в рамках примеров повторно это сравнивать не будем.


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

Примечание: текстура Hint используется только на видимых гранях, остальные — Skip.

А теперь посмотрим на видимость в следующих локациях:
Здесь проблема заключается в том, что визлисты слишком высокие и видят слишком много соседних. Поскольку весь уровень сделан под две высоты (128 и 256 юнитов) я сделаю 1 хинт с рабочей нижней гранью на 128 юнитах и верхней на 256, чтобы ограничить максимальную высоту всех визлистов в большой локации и туннеле, которые ниже них, на отметке 128 юнитов и 256 юнитов соответственно.


Ещё это поможет избежать перестроек брашей слишком высоко и позднее поможет использовать func_viscluster.


Итог: 17 и 26% прибавка в производительности в этих локациях за счёт 6 визлистов и 9 визпорталов и 1 хинта.

О маленькой локации: у неё нет областей выше 128 юнитов, а также все визлисты там уже не выше 128 юнитов. Протягивание хинта туда создаст только лишние визлисты на отметке 256 юнитов.

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


Примечание: дальше ограничивающий высоту хинт скрыт для улучшения видимости на скриншотах.






Есть ещё несколько вариантов мест, которые не применены в рамках примера, но где в теории можно было бы применить хинты, при необходимости. Их можно просмотреть на скриншотах:


Итог: прибавка к производительности ≈ 16,4%.
Раздел 15 — завершающее: примеры — часть 2
Работа с визкластерами
В примере нет каких-либо проблемных мест, где стоило бы применить визкластер, например, внутри помещений, но как и у любой полуоткрытой или открытой карты есть визлисты у неба, которые вполне можно назвать одним целым — разницы при переходе между ними почти нет, поэтому с ними и поработаем.

Размещать будем выше 256 юнитов, поскольку ниже мы обозначили игровую зону и отделили её визлисты от неба (в маленькой локации — выше 128).
Напоминание: при компиляции видно, что количество визлистов уменьшилось, но в самой игре они всё ещё на месте, но объединены между собой.

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

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

Работа с ареапорталами
Всего на карте есть 6 подходящих локаций для использования ареапорталов.

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

Разберём сперва те, где достаточно одного на каждую:






А теперь, где потребуется несколько:







Изменения:
  • Визлисты: 89 → 92.
  • Визпорталы: 173 → 174.
  • Производительность: +15,3%.
При этом может показаться, что в случае 1 и 2 (первые 4 скриншота) изменений почти нет. С конкретной точки это будет правдой, но ареапорталы больше важны при движении, а также работаю в обе стороны, поэтому здесь мы скорее улучшали не центральную точку (ей были места на скриншоте), а углы и производительность снаружи зданий (в случае 2 также второй этаж).

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








Итог: прибавка к производительности ≈ 14,8%.

Общие итоги изменений
  • Визлистов: 197 → 92 (53%)
  • Визпорталов: 554 → 174 (68%)
  • Среднее количество кадров за всю карту по маршруту:
    1 189 (макс. разница: 394) → 1 273 (макс. разница: 418) (6,5%).
  • Вес карты: 1,06 МБ → 915 КБ (15%).
  • Лимиты (только те, что поменялись):
    Элемент
    До
    После
    models
    brushes
    brushsides
    planes
    vertexes
    nodes
    texinfos
    texdata
    faces
    origfaces
    leaves
    leaffaces
    leafbrushes
    areas
    surfedges
    edges
    waterstrips
    waterindices
    LDR lightdata [variable]
    visdata [variable]
    entdata [variable]
    LDR ambient table
    HDR ambient table
    LDR leaf ambient
    HDR leaf ambient
    physics [variable]

    Total triangle count
    1
    171
    1 115
    462

    1 219
    385
    242
    28

    902
    468
    387
    1 090
    393
    2

    6 197
    3 605
    84
    1 275
    506 328
    10 455
    188 966
    387
    387
    1 792
    387
    63 949

    2 514
    2
    200
    1 293
    478
    1 123
    245

    250
    32
    663
    478
    248
    773

    410
    9
    5 365
    3 544
    69

    1 575
    368 656
    2 814

    190 812
    248
    248
    1 474
    248

    64 642

    2 119

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

То есть где что-то не справилось, справится другое: не справилось построение, скайбокс и func_detail? Попробуем хинты. Где-то не справились хинты? Попробуем ареапорталы. Где-то и они не справились? Попробуем окклюдеры!

Конечно, ваш путь оптимизации несколько иначе, но ни один процесс не стоит пропускать.
Раздел 16 — завершающее: мифы и заблуждения
1 — тестировать результаты необязательно
Большой ошибкой будет следование этому заблуждению, поскольку все элементы оптимизации могут «и лечить, и калечить».

При неверном использовании и отсутствии тестирования
  • хинт может привести к ухудшению скрытия рендера и бессмысленному увеличению визлистов и их порталов (следовательно скорости компиляции, лимитов и веса);
  • визкластер — склеить лишние визлисты и их порталы;
  • func_detail — раскрыть лишний рендер, который хорошо скрывался;
  • окклюдер и ареапортал — ни на что не повлиять, скрывать рендер там, где не нужно или вовсе увеличить нагрузку на производительность.
Это касается и всех других моментов в разных вариантов.
Тестирование — обязательное условие оптимизации.

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

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

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

Брашевые лимиты, которые затрагивают эти средства оптимизации, нас не слишком страшат: в Garry's Mod они значительно расширены и мы с бо́льшим шансом быстрее достигнем лимита вершин (vertexes) или граней (faces), чем затрагиваемых ими.

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

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

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

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

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

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

5 — размер текстур влияет на производительность
И да, и нет.
  • Нет: размер уже применённой текстуры в игре не влияет на производительность от неё.

    То есть может растягивать и ужимать как нам угодно в редакторе. Такое влияние действительно разве что в движке GoldSource, но не Source, с коим мы работаем.

  • Да: размер (разрешение) самой текстуры влияет на производительность.

    То есть текстура с разрешением в 4К явно не лучшая идея для создания уровней, поскольку обычные размеры текстур в Source варьируется в следующих разрешениях:
    • 64x64 (или меньше: чаще текстуры разработчиков, спрайты, мелкие декали и подобное)
    • 128x128
    • 256x256
    • 512x512
    • 1024x1024 (редко)
6 — длительное время компиляции VVIS является признаком плохой оптимизации
Вовсе необязательно.

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

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

Жертвование временем компиляции — нормально, если это действительно даёт приток производительности.

6 — оптимизация неважна, если нацелена на мощные компьютеры
У каждого игрока будет разные комплектующие и/или постоянная нагрузка на компьютер, а одно единственное визуальное дополнение по типу интерфейса может порой снизить количество кадров на 10% и более. Вроде немного, но что если оно не одно? А оно почти всегда не одно.

Помните: уровень — фундамент, на котором создаётся сервер или одиночная игра и он всегда будет наполняться чем-то, что его будет дополнительно нагружать.

Если ваш уровень будет создаваться в формате «ну, на моём мощном ПК ведь выдаётся 110 кадров», то при добавлении дополнений или нескольких игроков будет менее 40, не говоря уже о тех, у кого компьютеры слабее и они, вероятнее всего, не будут пользоваться вашей работой, поскольку на других картах те же дополнения будут давать приемлемые результаты.

7 — для компиляции хватит и быстрого режима(Fast)
Это частично правда для VRAD, поскольку сильно от этого обычно освещение не страдает, хотя и становится более квадратным и неточным, что может привести к ряду артефактов.

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

Ни в случае с VRAD, ни в случае с VVIS быстрый режим не является нормой и приводит к плачевным результатам. Его использование даже в рамках тестирования нежелательно.
VMF-файл карты

Для просмотра разных локаций пользуйтесь визгруппами: каждая локация, а также ряд их частей разделены на разные визгруппы.
Заключение
Если у вас есть вопросы, вам есть чем дополнить руководство или вы не согласны с написанной здесь информацией, пишите в раздел «Комментарии».

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

Если требуется прямая связь со мной на тему картодельства, прошу в мою деревушку:
Также приветствуются виртуальные подарки:
https://steamproxy.com/tradeoffer/new/?partner=171963934&token=wKGYQ2Yi
10 Comments
Satton(RU)  [author] 3 Sep @ 12:39pm 
Привет!

Вижу, что ты её уже нашёл внизу руководства. =)
DarkLu$ 3 Sep @ 11:01am 
Огромное спасибо за руководство:steamthumbsup::steamthumbsup::steamthumbsup:. А есть ли вообще русскоязычные группы по маппингу???
Titanovsky 5 Jul @ 6:58pm 
Не смотря на то, что гмод уже никому не нужен. Ставлю огромный лайкосик, эта статья очень бы мне помогла в годах 18-19, когда активно делал карты. Сатунчик большой молодец, что довёл свою идею до конца, я помню мы с тобой ещё в году 23 общались на тему "как было бы круто иметь гайд по оптимизации", и ты из своего любопытства и бенчмарков смог сгенерировать полезнейший контент :gmod:

Братанча, жду тебя в s&box и твою дотошность до картостроения тудой, тем более релиз планируется на Q1-Q2 в 26 году) :kb2_heart:

Дальнейших успехов!
Ty4a 20 Jun @ 10:18am 
полезнота в руководствах, спасибо
Satton(RU)  [author] 20 Jun @ 4:42am 
Всем спасибо за отзывы, всё читаю, очень приятно.

Не забывайте рассказывать друзьями и обязательно оцените руководство, чтобы оно не затерялось среди множества новых! :fshappy:
FamyCH 19 Jun @ 5:41pm 
P.S. Что не вместилось в прошлый комментарий
Как человек работающий 5 лет с движком заявляю Project-S херня, и автор реально большой молодец что всё внятно объяснил и даже оставил ссылки на прямую связь в случае вопросов, очень мало людей что могут на энтузиазме сделать такие полезные гайды, надеюсь увидеть дальнейшие полезные статьи от автора. Всем мира!
FamyCH 19 Jun @ 5:39pm 
Очень хорошее руководство по оптимизации для начинающих работать с движком Source! Подробно все описаны существующие методы оптимизации на уровнях для данного движка, и самое главное всё по существу как есть. Первый по истине адекватное руководство для оптимизации где автор действительно исследовал и показывал наглядно как работает, а не как всякие Project-Ass которые толком не могут ответить насчёт вопроса оптимизации и время пихают свои сомнительные услуги.

Всем творческих успехов!
maksumkolesnukov022 18 Jun @ 8:36pm 
Очень круто! привет от любителя оптимизированных лайтмапов 228
yermak 15 Jun @ 2:09pm 
Колоссальная и невероятно качественная работа! :missing:
tecno 15 Jun @ 10:29am 
красава!!! рекомендую данного человека, может помочь с твоей картой (улучшить или исправить баги)