EN
Дядя Миша
Дядя Миша
25 subscribers
goals
0 of 2 000 paid subscribers
Чем больше подписчиков, тем быстрее будет продвигаться разработка

История разработки. Часть 3.1 Uniform Mesh

В сущности, у XashNT есть две вещи, кардинально отличающие его ото всех остальных движков. О первой я уже кратенько рассказал - это система материалов. Второе - это формат Uniform Mesh, абстрактный мета-формат хранения геометрии и сопутствующих данных, который не имеет каких-то чётких рамок и жесткой стандартизации и может расширяться до бесконечности. Так же на базе формата могут быть с лёгкостью изготовлены новые прототипы для хранения тех данных, которые в настоящий момент не могут быть сохранены уже имеющимися средствами. И всё это по прежнему будет Uniform Mesh.
О самом формате я расскажу в заключительной части, а пока что мы вместе проделаем тот путь, который проделал я, когда шёл к этому формату. Вполне вероятно что подобной информации вы более нигде не найдете, поэтому статья доступна лишь для подписчиков наивысшего уровня, ну, собственно, как я и обещал в предыдущей заметке. Уж извините.
Напомню, что XashNT базируется на Xash3D. Это, повторюсь, не значит, что к окончанию разработки, там останется хоть что-то из первоначального кода,
но здорово помогает постоянно иметь под рукой рабочую версию и вести итеративную разработку. К тому же моим потенциальным пользователям в каком-то смысле тоже придётся проделать этот путь, конвертируя ресурсы в форматы, понятные новому движку. Так вот. В Xash3D, поскольку он был совместим c GoldSrc использовался формат уровней BSP30, который в свою очередь вырос из формата BSP29 от первого Quake. Отличие у этих форматов было только одно: в Half-Life использовалось цветное освещение. В принципе разработка нового движка у меня неоднократно срывалась как раз вот по этой причине - не хватало опыта и знаний для разработки нового формата уровней. Использовать старый формат не имело смысла, как потому что, тогда, получившийся
продукт уже нельзя было назвать новым движком (движок новый, а проблемы старые), так и по ряду фундаментальных причин, перечисленных ниже:
1. Слишком подробное BSP-дерево. Дерево, которое стремится уложить каждый полигон на ноду. Из-за этого размер дерева фантастически распухал даже для не слишком сложной (по современным меркам) геометрии, обход дерева стремился по времени к линейному обходу всех полигонов, то есть в нём просто исчезал смысл. Однако, поскольку, на это дерево было завязано практически всё, как в движке, так и в компиляторах, его нельзя было просто выбросить или заменить другим типом дерева.
2. Геометрия, оптимизированная, для программного рендеринга. Оптимизировать геометрию для видеокарт начали уже в 1999-м году, первым был Кармак с Quake3. Quake1 был сделан еще в то время, когда 3DFX еще находился в противозачаточном состоянии. Вполне естественно, что это сильно повлияло на выбор форматов, для хранения данных. С одной стороны это позволило их неплохо сжать в дисковом файле (экономия памяти во главе угла), с другой это был максимально недружелюбный для видеокарт формат. Полигоны с произвольным кол-вом рёбер, текстурные матрицы. Всё это приходилось налету преобразовывать в треугольники. Из-за того факта, что вертексы индексировались как позиция в пространстве без учёта текстурных координат и лайтмапы, она просто исчезала при загрузке в видеопамять - никто не хотел индексировать вертексы на лету, поскольку это могло сильно замедлить скорость загрузки уровней. Да и сам подход к построению лайтмап (один полигон = один кусочек атласа), в принципе не позволял говорить о сколь-либо эффективной индексации вертексов. Максимум, на что можно было рассчитывать - это два треугольника одного полигона, которые в исходном формате были квадратом стороны одного браша.
3. Невозможность процессинга любого другого типа геометрии, кроме брашей. Поскольку отсутствовало само понятие детальной геометрии (в более поздних версиях компиляторов, его всё-таки добавили, но без реальной поддержки на стороне движка, этот механизм лишь ускорил время компиляции, не повлияв на скорость отрисовки геометрии). В свою очередь, даже добавление довольно простых моделей из треугольников порождало кучу проблем, поскольку их было необходимо преобразовать в некое подобие брашей, в соответствии с форматом BSP30. Если вы знакомы с моими компиляторами, для Paranoia 2:Savior, то наверняка знаете, что я реализовал такую возможность включения полигональной геометрии в BSP-файл, однако с целым рядом оговорок. Во-первых, невозможность построения коллизии для таких типов мешей. Во вторых, поскольку текстурные координаты хранятся в текстурных матрицах, её в некоторых
случаях не удаётся подобрать, что в свою очередь приводило к расхождению в наложении текстур. В третьих, сама точность округления для брашей значительно меньше, нежели для полигонов, соответственно, в такой геометрии возникали щели в некоторых случаях. Ну и самое поганое - скорость отрисовки только лишь уменьшалась с каждой такой новой добавленной моделью.
4. Неадекватная современным реалиям система окклюдинга невидимых полигонов. Potential Visible Set, который включал в себя матрицу, позволяющую отсечь любой из одиночных полигонов на уровне. Матрица росла в геометрической прогрессии вместе с ростом полигонов. Не спасала даже RLE-компрессия и тот факт, что видимость полигонов была представлена битами. Разумеется, время расчёта такой матрицы тоже могло растянуться на несколько дней. Ну и самое главное - современной видеокарте проще нарисовать длинную секвенцию из стрипов, нежели выводить по одному треугольнику. Иными словами, вся проделанная работа была впустую и лишь ухудшала конечный результат. Разумеется с поправкой на текущие реалии.
5. Фиксированный набор хуллов для коллизии. В своё время красивая и изящная система, позволившая обрабатывать физику даже на слабеньких процессорах, типа 486DX, и капитально ограничвающая левел-дизайнеров в наше время. Мало того, что подвижная геометрия представлена лишь одним типом примитива - боксом, так эти боксы еще и фиксированного размера и этих размеров всего 2-3 штуки.
6. Неактуальный подход к наложению лайтмапы. В софтварном рендерере, этот механизм наоборот, позволял кэшировать только видимые участки, поскольку там геометрия должна была быть максимально тесселирована, чтобы не рисовать лишнее. Второй негативный момент - хранение лайтмапы в виде одномерного raw-массива. Если вы изучали код UE4, то вероятно видели там тип лайтмапы 1D - это отголоски еще тех самых времён. Лайтмапа, наложенная на одиночный полигон имеет свои уникальные координаты, которые не позволяют эффективно индексировать вертексы, а значит геометрия не подлежит стрипификации и будет выводиться медленее, чем могла бы. Особенно это касается полигональных моделей, где в таком случае пришлось бы, либо отказаться от лайтмапы вообще (и ограничиться вертексным освещением), либо использовать подход: один треугольник - один кусочек лайтмапы. Как это выглядит, вы можете посмотреть например, на уровне l02_stancia.bsp, это тестовая карта для Paranoia 2:Savior. Легко догадаться, что у нас не только геометрия теряет индексацию, но и получается двойной перерасход лайтмайпы, ведь один кусочк - это квадрат и в него можно вписать только один треугольник. Соответственно и лайтмаппер выполняет двойную бессмысленную работу.
7. Хранение избыточной информации - в частности рёбра полигонов. Хотя, это конечно, наименьшее зло из вышеперечисленного.
Подводя итог всему вышесказанному, сказать можно одно - формат этот по прежнему можно использовать, но для чего-то серъезного он уже не годится. Можно ограничиться лишь игрушечными сценами с пределом где-то в 50-100 тысяч полигонов, которые формат уже с трудом переваривает, но на этом и всё. Очевидно, что он не годится для моих задач ни в чистом виде, ни в модифицированном, ни в доработанном. Нужен другой подход.
Следующим на очереди всплывает формат от Quake3. Он уже более дружелюбен к видеокартам, однако тоже безнадёжно устарел. В сущности, часть проблем, у него осталась от формата Quake1. Неоптимальное наложение лайтмапы, старый код окклюдинга геометрии, поддержка полигональной геометрии с целым рядом оговорок (наложение лайтмапы либо невозможно, либо с ограничениями). К тому же, формат, сам по себе, не учитывал особенности видеокарт, что впрочем, на тот момент и не было актуальной проблемой. Практически все GPU не любят большие буфферы вертексов, предпочитая на лету разбивать их на блоки, размерами в 64 тысячи вертексов. Вполне логично, что эту операцию лучше произвести уже на этапе компиляции уровня, а не доверять драйверу видеокарты. В случае особенно больших буфферов (более миллиона вертексов), некоторые драйвера могут просто завершить приложение с ошибкой или отказать в загрузке по факту нехватки памяти. Так что в оригинальном своём виде, этот формат тоже непригоден для использования.
Далее можно обратить взгляд на формат от Doom3 (я перечисляю именно форматы движков от Кармака, поскольку, так уж исторически сложилось, что Quake-коммунити, в основном удерживается в рамках этих форматов, как наиболее простых, понятных и хорошо изученных, и я не стал исключением).
Здесь у нас, в первую очередь хранение уровней в текстовом виде, с дополнительными бинарными файлами. Всё это не слишком удобно для обращения, однако не принципиально. Формат от Doom3, делает много неактуальной, на сегодняшний день работы - в частности готовит геометрию для техники Shadow Volume, которая уже давно не используется, в силу своих ограничений. Однако там есть одно решение, которое не потеряло актуальности и сейчас. Я говорю о механизме отсечения видимости через порталы. Это хороший и понятный левел-дизайнеру механизм. На входе и выходе из комнаты, ставятся два портала, и комната превращается в геометрический сектор, который может быть выключен из процесса рендеринга за один вызов. Механизм определения полигонов, относящихся к внешней и внутренней части комнаты базируется на старой технологии portal flow, которая, в свою очередь завязана на BSP-дереве и была использована во всех предидущих версиях ID Tech. Но там, видимость определялась для каждого полигона отдельно, а здесь - для целых секторов. Т.е. время рассчёта такой видимости всегда занимает менее секунды, а максимальное кол-во порталов, которыми можно разбить уровень на секторы равно 16-битному лимиту и навряд ли будет когда-либо превышено художником. Правда остаётся необходимость в создании брашевой геометрии вокруг полигональной, если мы хотим добиться эффективного отсечения, однако это не составляет особенной проблемы. Так, например, на outdoor-уровнях, потребность в таком отсечении не возникает в принципе, там в дело вступают уже другие механизмы, например лоды и импосторы. Значит такой уровень будет состоять из одного сектора и расчёт видимости ему не потребуется. Более сложный случай - outdoor с подземельями. Здесь мы можем поместить наружную часть уровня в гигантскую коробку с небом, а в нижней её части пробить дыры, ведущие в эти самые подземелья, закрыв их порталами. Таким образом indoor и outdoor будут изолированы и когда игрок спустится под землю, то верхняя часть уровня перестанет рисоваться полностью. В свою очередь подземные коридоры, тоже возможно разграничить на отдельные сектора, но обычно в этом уже не возникает необходимости. Так же этот механизм, может помочь и для каскадной проекции теней, разом отсекая те поверхности, куда солнечные лучи достать не могут в принципе.
Рассмотрев и опробовав на практике всё вышенаписанное, я пришёл к выводу, что такая технология вполне отвечает моим требованиям и её можно использовать в новом формате уровней. Но это было только начало
большого пути.
Продолжение следует.

Subscription levels

$
No subscription levels
Go up