BSP, VIS и Оптимизация геометрии

В статье будет рассказано о том, что собою представляют и как работают программы vbsp.exe и vvis.exe из набора компиляторов SSDK. Также будут даны некоторые советы по базовой доработке карты, ускорению времени компиляции, использованию func_detail и проч. Знать подобное необходимо, если вы мапите не только для себя, и хотите, чтобы другие играли в ваши карты и не ругали вас плохими словами за тормоза. Элементарная аккуратность, понимание принципов действия 3d-движков, хорошая выдержка и терпение — уже неплохо для начала. Естественно, прежде чем лезть в эту область, следует освоиться с Half — Life 2 SDK, понять, зачем вам это надо, и готовы ли вы тратить свое личное время на эксперименты.

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

1. ТЕРМИНЫ

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

2 D : вершина, сторона, многоугольник

3 D : вершина, ребро, грань, многогранник (браш или solid)

Геометрия здесь — не школьный предмет, а обозначение для всех брашей, что делаются в Хаммере, и обычных моделей. Браши — World Geometry , модели — Mesh Geometry

Вертекс (Vertex ) — вершина. Обычно имеется в виду вершина треугольника

Рендер — та часть кода движка, что отвечает за вывод на экран геометрии, освещения, эффектов

2. B S P

BSP расшифровывается как Binary Space Partitioning  — Двоичное Деление Пространства. Обычно к BSP добавляется слово «tree» , из-за того, что BSP-структура похожа на дерево или куст, у которого от «стебля» (root node ) отходят «ветви» (nodes) . Такие определения используется почти в любом движке, и Source в их числе, только «node» называется «leaf» или " leaf node " или " PortalCluster "  — это все синонимы. [Писать по-русски точный перевод «лист» странновато и не совсем точно (лист плоский), поэтому в статье «leaf «называется «блоком».]

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

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

Сначала BSP-компилятор делит пространство карты на блоки (lea ves). Для деления нужно выбрать направляющие плоскости. Логично это деление производить вдоль граней основной геометрии. Блоки строятся там, где было пустое пространство между брашами. Получается, что браши и блоки дополняют друг друга. Иначе говоря, если на карте есть какой-то замкнутый объем, то он полностью заполняется многогранными зонами различных форм. Это первая стадия работы VBSP.

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

Тогда во время игры движок сверяется с BSP-деревом и рисует только те объекты/геометрию, что могут быть видны: а) в блоке, где находится игрок б) в блоках, видных из этого блока. Уже не требуется рассчитывать видимость отдельно для каждого элемента игрового мира — все сводится к проверке блоков.

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

В Source сделано исключение только для эффектов частиц — они прорисовываются всегда. На AI и физику тоже накладываются некоторые ограничения. Но это не главное. Важнее всего для производительности прорисовка и текстурирование треугольников, а они подчиняются главному правилу движка: «что не вижу, то не рисую» . Надо заметить, что слово «видит» для BSP значит не то же самое, что для человека. Роль глаз у блока играют numportals  — общие грани с другими блоками.

Сайт poligon. cs 2. ru располагает подробной статьей о видимости leaves. Поэтому не буду сильно распространяться на эту тему. Стоит сказать, что та статья писалась о QBSP 3 шестилетней давности, а VBSP от valve ушел далеко вперед в плане выбора оптимального деления блоков. Но большинство принципов, да и ошибки, компиляторов Quake 3(2) и Half — Life 2 похожи. Это же касается распространенной ошибки «leaf saw into leaf » [2 и более numportal 'ов принадлежат одному блоку, но видят друг друга]. У VBSP выше приоритет плоскостей, параллельных осям X, Y, Z, что дает почти правильную картину при его самостоятельной работе с прямыми брашами в закрытых пространствах. Но в иных случаях надо ему помогать — ручная оптимизация сократит время компиляции и уберет лаги.

Построить дерево относительно просто, но сделать его эффективным гораздо труднее. Процесс идет по некоторым правилам, которые по идее должны выдавать нормальный результат в любой ситуации — но это не так. Иногда даже не получается получить одинаковый результат при разных компиляциях, если, например, повернуть всю карту целиком на 90, 180, 270 градусов (т.е. ничего не меняя в самой геометрии) и запустить процесс заново. BSP -дерево на сложных картах может стать слишком ветвистым, если никак не помогать компилятору. Он не лишен ошибок, и иногда делает немного иначе, чем того ожидает логика. Чтобы ускорить работу и как-то уменьшить непредсказуемость вводятся ограничения компиляции.

Вот некоторые из них:

1. VBSP сразу исключает из своей обработки: а] Обычные модели (*. mdl) б] Брашевые объекты func _, trigger _ и остальные классы, за исключением служебных — func _ areaportal и func _ occluder в] Точечные объекты — entity (prop _, point _, env _ и прочие) г] Все браши с displacement . Остальные грани без displacement вообще удаляются.

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

2. Обязательна замкнутость блоков. Если обрабатываемый объем не является замкнутым и граничит с пустой, то VBSP не сможет создать блоки, а значит, не заработают программы по расчету видимости и освещения. Это всем знакомая утечка. * leaked * становится самой первой (и самой любимой) ошибкой при компиляции первых карт, и сопровождает маппера в течение всей трудовой жизни. Об исправлении утечек написано слишком много, но вряд ли они того стоят. Если у вас все в порядке со зрением, то . pts -файла будет достаточно (Map > Load Pointfile ), чтобы обнаружить ошибку. После его загрузки появится красная линия, указывающая на место, где VBSP не смог правильно создать портал — здесь и будет утечка.

Будьте внимательны при постройке уровня, проверяйте состыковку стен сразу. Старайтесь применять сетку минимум на 16 или 32 юнитов, когда размещаете стены — это не избавит полностью от ошибок, но работу упростит.

3. Пространство всегда разбивается на блоки по 1024×1024×16384 юнитов (в середине пространства уровня) и 1024×1024×8192 (ниже и выше середины) по темно-красным линиям. Среднестатическая карта довольно редко превышает 3000 юнитов в высоту, поэтому можно забыть о разрезе по оси Z. А вот с делением по осям X — Y (1024×1024) надо считаться с самого начала создания карты. Главное — грамотно располагать стены. В виде сверху следует выравнивать их боковые стороны по темно-красным линиям и стараться добиться совпадения угловых стен крупных комнат с линиями 1024×1024. Понятно, что каждую стену так не разместить, старайтесь убрать подальше наиболее сложные браши. Развернутый браш, расположенный на пересечении двух линий разреза, добавит десяток лишних блоков.

Так VBSP режет пространство по оси Z

По центральной (зеленой) линии деления нет

4. Сконструированная в редакторе геометрия может создавать свое leaf -разбиение только внутри ниженазванных объемов. При нарезке блоков движок в первую очередь обращает внимание на hint -браши и прямоугольные грани, параллельные координатным осям. Вдоль них проводятся начальные плоскости разбиения, и уж потом обрабатываются наклонные плоскости.

5. VBSP не поддерживает пересекающиеся браши. Если браши пересекаются, то не понятно, как создавать vis -блоки и рассчитывать видимость. Потому VBSP их режет, но какой из брашей нужно оставить, а какой урезать он определяет самостоятельно. Не факт, что он выполнит задачу правильно. Следите за этим делом при создании карты, правьте руками и не надейтесь на компиляцию.

6. VBSP не поддерживает вогнутые браши. Такие обычно получаются после использования Vertex Tool . Эту ошибку легко найти по Alt — P. Хаммер пишет Invalid Solid в таких случаях. Поддерживаются только выпуклые многогранники. У них нормали к граням не пересекаются ни в одной точке.

7. Координаты вершин многогранников, образующих браши должны быть целыми числами. В противном случае VBSP округлит дробные координаты до ближайших значений, но только при создании браша инструментом block tool . Например, 24-сторонний цилиндр шириной и длиной по одному юниту превратится в квадрат. То же самое случится, если создать достаточно большой цилиндр и потом уменьшить его до непотребных размеров, компилятор все равно выдаст ошибку (Invalid Solid Structure и/или Texture Axis Perpendicular to Face ). Перезагрузка карты в редакторе также выявляет эти просчеты. Если имеются неправильные браши, Хаммер пишет N solids wasn ' t loaded due to errors in this file .

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

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

9. Есть и другие условия. Наверняка я чего-то не знаю. Но основные условия перечислены. Можно еще действовать на отдельные стороны компиляции VBSP через параметры — вот непаханое поле для исследований.

Кстати, VBSP может сразу определить некоторые невидимые друг для друга блоки. Например, для двух замкнутых и ничем не соединенных объемов (комнаты, между которыми пустота). Пока находитесь в одном из объемов, движок не будет рисовать содержимое второго. Но вряд ли кто-то компилит карту одним VBSP. VVIS запускать нужно в любом случае — ведь внутри этих объемов необходимо производить расчет на видимость.

Не правила, но советы.

Компилятору приятнее работать с числами, кратными двойке, чем с нечетными. Это относится ко всем расчетам. Располагая основные стены карты по крупной сетке (64−1024), вы упрощаете BSP-дерево и избавляетесь от блоков там, где они не нужны — на открытом пространстве, например. Не надо думать, что подобная правильность вредит внешнему виду — есть множество других дизайнерских средств разнообразить карту.

Вершины фигур одинаковых размеров, созданных при помощи blocktool > arc и blocktool > cylinder часто не совпадают, и точно состыковать их трудно (Vertex Tool 'ом можно, но долго), лучше превратить их в брашевые объекты. И уж тем более не используйте их на границах карты. Окружающие уровень стены должны быть простыми и прямыми.

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

2.1 HINTS

HINT — это та самая поддержка VBSP, которую вы можете и должны оказывать. Грани брашей с текстурой tools / toolshint вызывают искусственное BSP -разбиение в нужном вам месте карты, получая от компилятора исключительный приоритет в делении блоков. Внутри объемов хинт-брашей разбиение во вторую очередь. Ограничения данных брашей те же самые, что и у обычной геометрии. HINT -текстура прозрачна и не делится на полигоны. Текстура tools / toolsskip наоборот исключает из обработки ненужные вам грани. Хинт-браши делят только блоки, но не полигоны на брашах.

Если вы поняли принципы BSP -деления, то необходимость применять HINTS не должна особо затруднить вас. Нельзя на все случаи придумать правила, куда ставить или не ставить хинт-браши. Компилятор — он непредсказуемый. Чтобы найти и исправить места неправильного или чересчур сложного деления придется запускать игру и ходить по карте с mat _ leafvis . Потом возвращаться в редактор, добавлять хинты, компилировать заново (конечно без VRAD, чтобы время не тратить), опять искать ошибки… И так пока не добьетесь нормального результата или вам не надоест. Научитесь — ошибок будете допускать меньше.

Думать о хинтах нужно после завершения постройки карты, на этапе доводки. И прежде чем ставить хинт-браши, надо проверить карту — может быть все нормально поделилось и без них? Бывает, что VBSP с первого прохода делает все как надо.

Но пару советов дать можно. Вот где VBSP иногда надо помогать:

1. Изредка приходится помещать хинт-браши в проемах дверей. Но здесь обычно VBSP сам правильно делит.

2. Обязательно нужно ограждать цилиндры и арки прямым хинт-брашем. Конечно, цилиндр должен быть достаточно крупным (>512 юнитов) и хоть что-то блокировать. VBSP ерунду наворотит, если этого не сделать — блоки вылезут далеко от цилиндра.

В приведенном примере создана круговая стена 1024×1024 с проемом внутри. Тут хинт обязателен — он помогает избавиться от неправильных блоков и отделяет проход в стене от наружных блоков. Чтобы увидеть неправильные блоки, попробуйте подобный объект скомпилить без хинт-браша. Разница должна быть заметна.

3. В некоторых типах помещений будут получаться такие зоны, из которых видно все остальные блоки. Например: в подъездах; в крупных комнатах, соединенных с более мелкими; на улицах. Как не расставляй хинты — толку не будет, если есть прямая видимость между блоками. Можно сгладить недостатки, правильно разместив хинт-браш, так чтобы он отделял основную проблемную зону от других.

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

2.2 Брашевые полигоны. (Solid polygons или Wpolys )

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

Деление на треугольники придумано давно, опять-таки в целях облегчения работы видеосистемы. С треугольниками просто работать: любой из них задается в математическом виде 4 числами — 3 числа задают перпендикуляр к плоскости — нормаль и одно число определяет положение центра. Чтобы узнать, нужно рисовать треугольник или нет, движок измеряет угол между линией взгляда и направлением нормали, и если угол оказывается равным или больше 90 градусов то треугольник исключается из обработки. Если меньше, то в дело вступают прочие приемы — проверка по BSP-дереву, occluder, z — buffer и проч., и если уж после этих проверок треугольник оказывается видимым, то он текстурируется и освещается. На текущий момент ничего столь же удобного и быстрого не придумано, так что без полигонов не обойтись.

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

VBSP делит поверхности на полигоны по нескольким принципам:

[Вообще, эта операция проводится первой, а деление на блоки идет во вторую очередь.]

1. В первую очередь выполняется обязательное нарезание по красным линиям: X — Y =1024×1024, так же, как это делается с блоками.

2. В местах соприкосновения (совпадения плоскостей) граней разных брашей. Эту операцию называют «Face Merge » . Когда грани совпадают полностью, они сразу удаляются из обработки (т.е. исключаются из обработки текстуры этих граней), если нет — VBSP производит дополнительное деление на полигоны, пока не добьется совпадения. С прямоугольниками эта операция проходит неплохо. Хуже с неправильными многоугольниками.

Типичный пример неудачного разбиения — совмещение оснований цилиндра и параллелепипеда. Например, чтобы исключить многоугольное основание 12-стороннего цилиндра (-9 полигонов), компилятор превращает прямоугольную грань браша в месиво из треугольников (+12 полигонов вместо положенных двух). Недостаток вроде небольшой. Но с брашами сложной формы число полигонов возрастает в разы, тут счет на десятки полигонов. Единственное решение — использовать func_detail, и нижнее основание цилиндра закрасить nodraw .

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

В верхней грани — сотни полигонов. В данном случае это необходимо для нормального освещения. Проблема в том, что на боковой грани, где изначально было всего по два треугольника из-за доп. разбиения стало уже 18 полигонов. И так на каждой соседней грани. Убрать само деление никак не получится. Разве что закрасить боковые грани текстурой nodraw .

4. В первом Half — Life разбиение определялось основной текстурой поверхности, ее масштаб прямо влиял на количество полигонов. Нужно было помнить о разных размерах разреза для тайловых/нетайловых текстур, знать о «224×224» и «240×240 cut «и пр. Source позволяет забыть об этих ограничениях, но и вносит новые. Одна текстура независимо от размера и масштаба может принадлежать сколь угодно большим полигонам и не вызывать дополнительного разбиения. От ее Texture Scale число треугольников не зависит. Что с 0.25, что с 4 — картина одна. Но деление на полигоны все же есть. Почему? Потому что теперь оно задается текстурой lightmap , а не основной текстурой с изображением. Разделение осталось на своем законном месте, но следить надо за другими параметрами.

2.3 LIGHTMAP

Lightmap (карта освещенности)  — это индивидуальная текстура поверхности браша, содержащая информацию об уровне его освещенности и цвете. Расположение lightmap привязано к глобальной координатной сетке, а не к координатам браша, и потому не может меняться. У них изменяется масштаб (Scale ) в пределах целых чисел (Хаммер округляет дробные значения); числа, кратные 2, как всегда предпочтительнее. Ниже масштаб — выше точность расчетов освещения и четче тени.

В режиме просмотра «3 D Lightmap Grid » lightmaps отображаются как бело-синяя сетка для масштаба 16 (т.е. в 16 раз больше единичного размера) и желто-синяя для иных значений. Именно lightmaps определяют полигональное разбиение поверхности. Каждые 32 квадратика этой текстуры создают один lightmap -квадрат , в котором далее производится деление на 2 треугольника. Чем больше Lightmap Scale , тем больше этот квадрат и тем меньше треугольников. В принципе ни их форма, ни размер на освещение никак не влияют, lightmap  — не зависящая от полигонов текстура. Но раз VBSP это надо, значит на то есть своя причина — он так работает.

Границы теней при разных Lightmap Scale . Здесь одна клетка обычной текстуры — 32 юнита. Заметно, что ширина размытой полосы между освещенной/неосвещенной зонами точно равна значению Lightmap Scale .

Минимальный масштаб lightmap  — 1×1 юнит. Наименьший размер lightmap -квадрата — 32×32 юнита. Ставить такой Lightmap Scale в реальных картах, конечно нельзя. Во-первых, полигонов получится огромное число, во-вторых — смотрите ниже. Lightmap Scale по умолчанию равен 16:1, и освещение выходит прямо-таки не очень: получаются размытые, ступенчатые тени. Использование меньшего масштаба выглядит заманчивым, но давайте посмотрим, сколько места на диске (а потом и в памяти) отнимет одна крупная текстура lightmap .

На карте я поместил один браш 2048×2048×1024 юнитов и все его грани закрасил nodraw, кроме верхней, размером 2048×2048 юнитов. Таким образом, на вес карты влияла только эта грань. Компилировал как одним VBSP, так и VBSP с VRAD (1 источник света). Записывал размеры одного и того же. bsp при разных значениях масштаба lightmap . Вот результаты:

Lightmap Scale

Размер карты (кб) Только VBSP

Размер карты (кб) VBSP+VRAD

64

34

52

32

34

102

16

38

320

8

47

1150

4

76

4460

2

184

17650

1

616

70430

Сравните числа. Разница чувствуется. В последних случаях негативный эффект удваивается: во-первых полигонов 2000–5000 штук, что бьет по видеокарте, во-вторых памяти тратиться слишком много — до 70 Мб.

О длительности компиляции VRAD и говорить нечего — потому он долго работает и отъедает много памяти, если есть поверхности с малым lightmap scale . На масштабах 64−4 уходило не более 15 секунд на полную компиляцию, в последнем случае — 3 минуты. И только на одну грань браша. Так что 16:1 поставлено не зря. Уменьшать масштаб убийственно для веса готового bsp -файла и производительности (lightmaps ведь загружаются в память все разом). Оставьте как есть. Но тогда о четких тенях придется пока забыть. Сейчас это труднопреодолимое ограничение. Нужно выбирать между скоростью и качеством — обычно выбирают первое.

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

Да еще: по несложным расчетам можно найти, что на 1 квадрат текстуры lightmap любого масштаба тратиться 16 байт — как раз для задания цвета в RGB .

2.4 Служебные текстуры

Служебные текстуры — это текстуры из materials / tools . К теме статьи относятся только 3 из них:

1) toolsblack  — равномерный черный цвет. Не отражает света. В остальном — обычная текстура. Разбивается и текстурится как положено, поэтому лучше ставить Texture и Lightmap Scale на максимум.

2) toolsnodraw  — прозрачная текстура, но только для взгляда. Браши с этой текстурой учитываются всеми компиляторами, т.е. вставляются в BSP -дерево и обрабатываются VRAD 'ом как обычные непрозрачные браши. Главный плюс — браши не разбиваются на полигоны. Отсюда применение: toolsnodraw желательно

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

d 1_ trainstation _02 — нагруженная карта, особенно

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

3) toolsskybox  — прозрачная текстура неба. Материал не издает звуков при выстрелах/действии физики. На полигоны не делится. VRAD эту текстуру не обрабатывает. Можно использовать вместо toolsnodraw , когда не требуется освещение.

3. V I S

В ХЛ2 компилятор VBSP.exe только разбивает поверхности на треугольники и создает BSP -дерево. Функция по расчету видимости отделена от BSP -компилятора (кроме самой примитивной), за нее отвечает компилятор VVIS. exe. Он работает не напрямую с картой, а с prt -файлом, который генерирует VBSP в случае удачного завершения своей части работы.

Самая трудоемкая и долгая часть работы приходиться именно на этот это приложение. VVIS выполняет построение PVS (Potentionally Visisble Set — Потенциально Видимый Набор [ Numportals ]) для каждого блока. PVS определяет видимость каждого из блоков относительно остальных.

Чтобы построить PVS, компилятор VVIS делает проверку на видимость numportals. Упрощенно можно представить ее так: если между двумя разными numportal`ами можно провести ничем («ничем» = брашевая геометрия) не пересекаемую прямую, то те portalcluster 'ы к которым принадлежат numportal 'ы будут видны друг другу. Соответственно, если ни при каких условиях все numportal 'ы двух portalcluster 'ов не могут быть видимы, то блоки считаются взаимно невидимыми и имеют непересекающиеся PVS. Пока вы находитесь в одном из них, содержимое другого блока (модели, браши) не рисуется. Однозначно определяются разные PVS для двух блоков, разделенных пустотой. Но как говорилось, с этим справляется сам VBSP. Сам VVIS особых построений и изменений геометрии не совершает. Он только добавляет PVS к уже созданным блокам и ничего более. VVIS имеет дело с тем, что ему выдает VBSP, поэтому его скорость прямо зависит от правильной работы маппера.

Пример расчета VVIS. Numportal 'ы — зеленые линии. Блок, для которого определяется PVS , выделен красным цветом. Те блоки, что входят в его PVS  — оранжевым, невидимые блоки — черным. Видимые блоки найти просто — между красным и любым оранжевым блоком проводится прямая. Здесь два разных блока и два разных PVS .

Еще иногда встречается фраза " per PVS " (на один PVS). Например, шейдерная вода определенной высоты обязана быть в одной на PVS — это значит, вода с другой высотой не должна принадлежать тому же PVS, что и первый браш воды. Еще есть мнение, что динамический свет (light _ dynamic ) должен быть одним на весь PVS, но лучше проверить самостоятельно на своей карте — иногда и правда тормозит, иногда нет.

Кстати, местная навигация, для которой не требуются info _ nodes , работает как за счет PVS, так и BSP. Годится она только для поиска укрытий и нескриптовых целей, типа противников. Спасибо и за это. У класса NPC _ присутствует флаг " Think outside PVS " , его активация позволяет интеллекту NPC обнаружить игрока, когда тот не видим для них по BSP -дереву. Без включенной галки " Wait for script " , противники с момента респауна начнут стрелять по игроку, попытаются добежать до него или займут оборонительную позицию, в зависимости от AI.

VVIS еще рассчитывает PAS  — Potentially Audible Set (Потенциально Озвучиваемый Набор), но это дополнение к PVS. По размерам блока компилятор определяет тип помещения и применяет для него одну из нескольких предустановок DSP (эхо + эффекты искажения звука). Установки прописаны в файле dsp _ presets . txt в папке hl 2/ scripts . Во время игры звуковой движок автоматически меняет эти установки при переходе из блока в блок. Прислушайтесь, когда будете играть, — заметите небольшую разницу в эффектах взрывов и выстрелов внутри разных помещений. В длинном коридоре с высокими потолками эхо должно звучать дольше, чем в маленькой комнате, отзвуки в шахте лифта звонче обычных и т.д.

В игре будут полезны следующие команды:

mat _ leafvis «0−1» // VIS -блок, в котором вы находитесь, обводиться красными линиями по контуру

mat _ wireframe «0−3» // Показываются полигоны на геометрии и моделях. Режимы 1−3 различаются

+/- showbudget // Главный инструмент измерения производительности

r _ draw decals \ disp \ particles \ water \ detailprops \ staticprops \ «0−1» // Команды из одной серии. Отключают прорисовку отдельных элементов карты. Иногда полезно для тестирования, когда нужно посмотреть, как меняется fps от добавления чего-то тяжеловесного на карту.

4. FUNC _ DETAIL

Несмотря на то, что объект func_detail входит в список entities, он никаким объектом не является. Это нечто промежуточное между обычными брашами и настоящими объектами. Detail — это свойство одного или нескольких сгруппированных брашей. Изготавливаются просто — выделите нужные браши, нажмите CTRL — T и выберите func_detail .

У этого класса отсутствуют аутпуты и обычные поля, кроме Minimum DX Level и Maximum DX Level . Они задают мин/макс уровень графики (параметр dx_level ), при котором этот браш будет загружаться в игре. Если вы хотите, чтобы на хилых компах c dx 6-видеокартами не показывались некоторые чисто декоративные детали, то изменяйте. Но вряд ли вам захочется, чтобы у кого-то отключались стены и окна func_detail — в таких случаях лучше оставить default и не морочить себе голову.

Существенное отличие от стандартных брашей состоит в том, что func_detail не участвует в создании BSP дерева. Т.е. не разбивают другую брашевую геометрию на полигоны (wpoly) и не загораживают обзор. Если разные func _ detail пересекаются , то к ним применяется свое отдельное от solid -геометрии разрезание D etails Merging» ). На полигоны func_detail делятся по тем же правилам, что и обычная брашевая геометрия, правда, удаляются далеко не все невидимые поверхности — с этим придется мириться.

Рендер света VRAD также учитывает эти объекты. К ним применяется то же освещение, что и для геометрии. Но есть но. В месте соприкосновения func_detail с обычным брашем не производится face merge и не удаляются лишние полигоны, из-за чего у самого края появляется светлая полоска. Можно сгладить этот недостаток хорошей текстурой или понизить lightmap scale плоскости, на которую падает тень, но полоса останется. Мелочь, но имейте в виду.

Выигрыш от грамотного использования func_detail получается огромный. Плюсы — упрощенное BSP -дерево и меньшее количество wpolys. Минусы — лишние текстуры.

Кандидаты на превращение в func_detail:

1. Почти любой декоративный браш размером меньше 128×128×128, особенно находящийся на открытом пространстве. Если игроку требуется 1 секунда, чтобы обойти препятствие, следует ли нагружать компиляторы его обработкой? Крошечный куб 1×1×1 посреди пустой комнаты дает 6 portalclusters и 12 numportals, но ничего блокирует. Толку ноль, а BSP -дерево усложняет и компиляцию затягивает.

2. Все браши с прозрачными текстурами (обозначены значком Т в браузере материалов). Они не блокируют видимость в любом случае. VBSP выдаст «leaked» , если применить такую текстуру на стену, граничащую с пустотой.

3. Большинство наклонных, цилиндрических, арочных брашей и все сферы. Уже говорилось о плохих последствиях для компилятора BSP от использования подобных объектов. Если вам нужно круглое отверстие или туннель в стене, не делайте carve цилиндром в браше. Постройте обычный коридор с прямыми углами и поместите туда круговую арку- func_detail .

4. Почти все повернутые браши. Не забывайте, что даже прямоугольник поворачивается так, что его вершины имеют дробные значения, а VBSP это неприятно. Если все же необходимо сделать обычную брашевую стену под углом, то желательно передвинуть ее вершины в узлы сетки вручную Vertex Tool 'ом.

Практические примеры func_detail: дверные косяки, рамы окон, балконы, крыши домов, трубы, балки, колонны, лестницы и т.д. Почти вся геометрия, кроме стен.

Впрочем, другая крайность — карта с одними func_detai l  — не лучше . Такое их достоинство, как невлияние на деление полигонов у брашей, может стать и недостатком. Например, ящик, прилегающий к стене, после конвертации в func _ detail не будет разбивать полигоны на поверхности стены, но тогда из стены не вырежутся полигоны с текстурой и VRAD станет освещать их как положено. В игре рендер будет рисовать эту невидимую глазу поверхность.

Возникает вопрос, что хуже, дополнительные numportals или лишние текстуры? Трудно сказать. Когда как. Считается, что проверка видимости отнимает меньше времени, чем текстурирование. Если сомневаетесь, стоит ли использовать func_detail (или модель вместо него), скомпилируйте карту или ее часть дважды: без func_ и с ним — и сравните производительность. Заметите различие — определяйте по ситуации, что лучше. Чтобы превратить брашевый объект обратно в геометрию — CTRL-SHIFT-W или Move to World .

Как альтернативу, вместо func_detail можно использовать func_wall или func_brush. Но это уже полноправные entity. Они также не учитываются VBSP и не блокируют видимость, но и не отбрасывают теней на геометрию. К ним не применяется ни стандартное брашевое, ни собственное полигональное деление. Они отъедают entdata (часть памяти, отводимой под информацию об entity: имя, флаги, I / O и др.), поэтому эти 2 класса стоит использовать только тогда, когда взаимодействия действительно необходимы или не нужна тень.

5. XSI против HAMMER

Valve рекомендует использовать для декораций модели, созданные в 3д-редакторе, а не геометрию из Хаммера. Совет полезный, но отнюдь не обязательный для выполнения. Чрезмерное количество высоко-полигональных моделей на уровне тоже способно испортить FPS, что нехорошо. Стоит соблюдать баланс и стараться равномерно распределить потери производительности по различным «отделам». Графики из showbudget показывают, что движок неодинаково воспринимает разные виды геометрии: за отображение " brush model geometry " , " static prop geometry " , " other model rendering " и т.д. отвечают разные алгоритмы рендера.

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

Не скажу со 100% уверенностью, но кажется VRAD работает с shadowvolumes  — определенные объемы, для которых определена освещенность и направление света от источников light и light _ environment (судя по тому, что VRAD не выполняет Light Bounce без VVIS и пишет при компиляции BuildVisLeafs , так оно и есть). При попадании центра модели (именно центра, а не ее части) в объем, движок проверяет, какие источники света освещают этот объем и уж затем рассчитывает освещенность и ее направление для всех полигонов модели. В плане качества это полумера, особенно в сравнении с динамическим освещением, тяжелым для Source. Оттого заметны переходы между объемами — свет меняется резко, и модель иногда выглядит неправильно.

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

Движущиеся брашевые модели тоже подвержены подобной «болезни». Учитывая то, что расчет lightmap для них проводится 1 раз, сдвиг объекта из его начального положения нежелателен, так как получается довольно нереалистичное зрелище. У func _ door , func _ physbox , func _ train и т.д. возможно лучше активировать параметры Disable receiving shadows и/или стараться не допускать перемещения func _* из одной зоны освещения. Хороший вариант — env _ cubemap , но эта штука нагружает swap buffers (как и отражение/искажение воды, фонарик).

В итоге, может оказаться, что брашевые декорации экономичнее модельных (не всегда!). Так что используйте возможности с умом. Прежде чем ставить на карту красивую крышу или разрушенную стену в 4000 полигонов, подумайте, долго ею будет любоваться игрок, и важна ли модель для геймплея? Да — оставляйте модель. Нет — смело заменяйте prop _ static на брашевую модель, сделать которую и проще и быстрее. В маппинге лучше сочетать оба типа геометрии, чем отдавать полное предпочтение чему-то одному.

6. SKYBOX

Если вы приучились «исправлять» утечки с помощью постройки вокруг уровня гигантской коробки, то скорее избавляйтесь от этой вредной привычки. Skybox скора на изготовление, но медлительна в действии. Да, браши с текстурой toolsskybox не подвергаются полигональному разбиению; да, вы сразу убьете кучу проблем с перепланировкой проблемных частей карты, но высокой ценой. Она не убирает утечки, а добавляет кучу ненужных vis -блоков в карту — ведь в BSP -дерево войдут и те блоки, что находятся снаружи, между стенами и skybox. Эти блоки не нужны, но будут рассчитываться по всем правилам. К тому же невидимые поверхности снаружи брайшей не исключаться.

В некоторых случаях гигантская SKYBOX логически оправдана — на открытых пространствах, но только там. Чаще идея карты заключается в симуляции ограниченной естественными преградами локации, будь то коридоры базы или улицы города, что является простой задачей для VBSP и VVIS. Изначально планируется вполне замкнутое пространство. А потом, при первой же утечке сооружается SKYBOX и уровень превращается из коридорного в открытый тип, который так недолюбливают Source компиляторы. Хрупкая гармония рушится, размер карты необоснованно возрастает и fps падает. Страдаете тем же — переучивайтесь и не ленитесь искать утечки, благо инструменты есть.

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

7. ЗАКЛЮЧЕНИЕ

Может показаться, что оптимизация не всегда обязательна, ведь карта у вас запускается, все идет плавно…

Но не у всех игроков стоят такие же видеокарты, процессоры, память как у вас. Задумайтесь о слабых машинах, которых немало. Да, 100, 500, 1000 лишних полигонов или 100−200 блоков не сильно скажутся на производительности. Но если карта велика и на ней есть открытые пространства, то брашевые полигоны начинают сильно портить жизнь рендеру. С избыточным количеством треугольников и блоков можно и нужно бороться. Наиболее доступный метод — уменьшение числа и сложности брашей (простота приходит с опытом) и правильное их размещение относительно друг друга.

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

Ссылки. Все на английском:

http://www.valve-erc.com/srcsdk/

Valve Hammer Editor Reference

http://www.hl2world.com/wiki/index.php/Optimization_(Geometry)

Half — Life 2 World WIKIpedia. Энциклопедия терминов по 3 D -графике и маппингу в Халфе

http://www.cs.wpi.edu/~matt/courses/cs563/talks/bsp/document.html#intro

История и теория BSP

https://www.opengl.org/archives/resources/code/samples/bspfaq/index.html

http://www.gamedev.net/reference/articles/article657.asp

FAQ по BSP -построению

http://www.bluesnews.com/abrash/

Ветеран id Software, Майкл Абраш расписывает технологии Quake 2 Engine.

Не про Source, но очень познавательно.

http://www.gamedev.ru/articles/?id=30128

Неплохая статья. Больше программинга, чем маппинга

Автор: Клава Коваленко aka [27].
26 марта 2005, 21:09