Дядя Миша

Дядя Миша 

Разработка игрового движка XashNT

26subscribers

15posts

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

История разработки. Часть 2.1 Material System

Сперва хочу уточнить один момент, который вероятно вызывает недоумение у части подписчиков. Я же обещал публиковать подробные отчеты исключительно для расширенной версии подписки, а они на данный момент доступны на всех уровнях. На самом деле тут нет противоречия, поскольку на данный момент я пишу отчёты о работе, проделанной еще до появления этого блога, это работа, которая велась в 2019-2020-х годах. Когда я доберусь до подробных отчётов о том, что было сделано в этом году, эта информация будет доступна только третьей категории подписчиков, а для первого уровня - просто краткое перечисление.
Итак, система материалов. Для любого современного движка её концепция является чуть ли не главным компонентом системы, поскольку от нее напрямую зависят возможности, которые движок предоставляет пользователю. Разверну свою мысль. Независимо от наличия исходников, гибкость движка в первую очередь определяется тем, что может с ним сделать пользователь, обладающий минимальной квалификацией в области программирования. Художникам и дизайнерам в любом случае приходится расширять свои навыки, например писать плагины на скриптовых языках для редакторов, возможно что и составлять шейдеры. Но на этом их пределы компетенции и оканчиваются, что разумно. Если человек начнёт углубляться в технические дебри, у него просто не останется времени для, собственно, творчества. Какие-то игровые объекты на уровнях (если это конечно не NPC со сложным поведением), обычно удовлетворяют достаточно примитивному логическому набору условий и могут быть созданы дизайнерами логики игры на каком-либо скриптовом языке, используя визуальные редакторы.
Этот подход в сфере игровых движков давно отлажен и вопросов не вызывает. С системой материалов всё сложнее, этот механизм в первую очередь затрагивает принципы аппаратной растеризации и хранения данных в видеокарте, на 100% абстрагироваться не получится, даже спрятавшись за драйвером видеокарты и прослойкой в виде системы материалов. К тому же, поскольку таковая система обычно затрагивает всю архитектуру, в ней может таиться принципиальная невозможность реализации каких-либо вещей, неочевидная разработчику на первый взгляд. Со всем этим приходится сталкиваться уже пользователям. К тому же концепция может поменяться вместе с версией движка, а ведь совокупность материала с текстурами и шейдером представляет собою ассет, который вполне может продаваться в виртуальном магазине за вполне реальные деньги. И вот с обновлением работа дизайнера превращается в тыкву. Есть еще один немаловажный момент - язык описания материала. Если он слишком прост, то у такой системы скорее всего будут большие ограничения. Если он сложен - повышается порог вхождения. Язык может изобиловать избыточным синтаксисом, что автоматически делает пригодным для редактирования только через визуальный редактор.
Полагаю я описал основные проблемы, которые стоят перед разработчиком концепции системы материалов. Лично для меня это был весьма непростой путь, он занял несколько лет, я придумывал одни концепции, проверял их в деле, начинал всё заново, искал ответа в сторонних движках, но вариант, который мне наконец понравился, появился лишь осенью 2019-го года и прошёл окончательную шлифовку в декабре 2019-го.
Но обо всём по порядку.
Сперва совершим небольшой исторический экскурс и посмотрим как обстояло с этим дело много лет назад. В Quake Engine никакой концепции
материалов попросту не было. Но в отличие от ID Tech, где соответствие материалов визуальным эффектам было жестко прописано прямо в коде
игры, здесь допускалось некоторое управление со стороны пользователя. К примеру, можно было создать текстуру, имитирующую небо, её имя должно было начинаться со "sky". Текстуры, имеющие в начале имени звездочку * создавали эффект завихрения и использовались для иммитации воды. Так же на эти текстуры не влияло освещение. Наконец, используя некоторые цвета из фиксированной палитры, можно было создавать эффект самосвечения отдельных пикселей на текстуре. Собственно, на этом возможности по управлению материалами и заканчивались.
В Id Tech 2 (Quake II), появляется собственный формат текстур, который, кроме пикселей изображения, содержит еще и некоторые настройки,
которые могут влиять на внутриигровую физику (скользкие поверхности, лестницы), создавать визуальные эффекты (полупрозрачность, движение
текстуры в заданном направлении), так и значения для излучения света от этой текстуры. Почти все настройки были оформлены в виде чек-боксов, их количество было жестко привязано к разрядности 32-битных переменных, из чего естественным образом вытекала сильная ограниченность возможностей таких материалов. Вполне вероятно, что именно этот подход в своё время оказал влияение на разработчиков из Epic Games, потому что, насколько мне известно, там до сих пор система материалов хранится в бинарном файле и её нельзя отредактировать используя текстовые редакторы. Но если я не прав и в UE с тех пор что-то изменилось, то поправьте.
Общая концепция того, как должен выглядеть cкрипт материала впервые появилась в Id Tech III (Quake 3) и была разработана Джоном Кармаком. Система выглядела как поименованный блок фигурных скобок, внутри которого допускались безымянные блоки фигурных скобок. Имя блока могло означать как имя материала, так и имя текстуры, из чего следовало, что оно выглядело именно как путь к этой текстуре. В 1999-м году подобный подход вполне имел право на жизнь, поскольку для большинства материалов применялся материал по умолчанию: диффузная текстура + лайтмапа. Этот материал был жестко встроен в код самого движка и не поделжал какой-либо модификации. Если бы пользователь захотел изменить какой-то из стандартных материалов (без пользовательского блока в скрипте), ему бы пришлось сперва его самостоятельно воспроизвести и только потом делать в нём необходимые изменения. Типичный блок описания материала выглядел примерно следующим образом:
textures/gothic_wall/iron01_f
{
qer_editorimage textures/gothic_wall/iron01_f.tga
{
map $lightmap
rgbgen identity
}
{
map textures/gothic_wall/iron01_f.tga
blendFunc GL_DST_COLOR GL_SRC_ALPHA
rgbGen identity
alphaGen lightingSpecular
}
}
Материал не поддерживал какие-либо выражения, здесь используется концепция "ключ-значение" (key-value). Зарезервированные префиксы
могли использоваться для каких-то других приложений рабочего процесса. Так, например, префикс "qer_" был управляющим словом для редактора уровней, а префикс "q3map_" - для компилятора этих же уровней. Таким образом была реализована концепция единого источника данных на разных этапах обработки. Сами команды внутри материала представляли из себя как смесь прямых указаний драйверу видеокарты (к ним, например относятся такие как blendFunc, alphaFunc или depthFunc), так и абстракции, поддерживаемые непосредственно игровым движком ID Tech III (команды map для загрузки текстур, rgbgen, alphagen для генерации цвета по заданным формулам). На момент выхода в свет ID Tech III, абсолютно все видеокарты имели фиксированный конвейер рендеринга, а концепция пользовательских программ, которые могут быть загружены непосредственно в видеокарту, еще только зарождалась. Поэтому формат описания материала оказался жёстко привязанным к особенностям работы именно фиксированного конвейера видеопроцесора, хотя людям далёким от знакомства с архитектурой видеоядр, подобные мысли попросту не приходили в голову. Тем не менее с точки зрения самих художников и дизайнеров формат оказался довольно успешным, под него были созданы пользовательские визуальные редакторы, формат получил дальнейшее расширение в Id Tech IV (Doom 3), где в него были добавлены регулярные выражения, а так же возможность загружать исполняемые программы для GPU - шейдеры. На тот момент их функционал был сильно ограничен, а пользовательские подпрограммы использовались параллельно с фиксированным функционалом конвейера, поэтому изначальная заточенность материалов под фиксированный рендеринг не создавала особенных проблем.
Движки от Id Software пользовались достаточно широкой распространённостью вплоть до конца 10-х годов, когда на сцену уже вплотную заступили представители большой тройки Unreal Engine, Unity, CryEngine. Одну из финальных итераций вышеописанной системы материалов мне так же пришлось наблюдать в игре Wolfenstein 2009. Движок данной игры использовал сильно переработанный ID Tech 4, в котором было применено отложенное освещение. Это в свою очередь еще сильнее затруднило использование первоначальной концепции из 1999-го года, в результате описание материалов обросло рядом ключевых слов, перекрёстных ссылок на другие блоки конфигурации и простая и когда-то вполне понятная система подошла к своему логическому тупику. Я не занимался её изучением достаточно подробно, но предполагаю, что её освоение без чтения документации будет сильно затруднено из-за массы неочевидных аспектов, обусловленных, как применяемой моделью рендеринга (отложенным освещением) так и потребностью увязывать разные стадии рендеринга в единый материал, одновременно учитывая какие-то дефолтные шаблоны, которые вполне по старой традиции могут быть до сих пор встроены в программный код самого движка. Тем не менее данный формат описания материала до сих пор пользуется определённой популярностью, главным образом обусловленной открытостью исходников Id Tech и возможностью использования этой концепции в самописных движках. Скажу так же несколько слов относительно систем материалов большой тройки.
Unity:
Концепция их материалов, если я ничего не путаю, была создана еще в 2005-м году и вероятно тоже не сильно изменялась. Разумеется у них есть визуальный редактор, но большинство параметров имеет фиксированные значения, жёстко определённые в коде. Так же используется мультипроходность рендеринга, но в данном случае это подсказка о типе конвейера - прямое или отложенное освещение. В системе изначально присутствуют дефолтные материалы и шейдеры, есть возможность подгрузки пользовательских. Как я понимаю, концепция базируется в первую очередь на том факте, что большинству материалов просто нужна реалистичная модель освещения (PBS), а в особых случаях можно использовать кастомные шейдеры, написанные дизайнером. Не берусь оценить гибкость данной системы, поскольку не работал с ней. Но если из моих подписчиков кто-то имеет подобный опыт, то может написать свои впечатления в комментариях.
CryEngine:
Насколько я понял из изучения исходников, многие шейдеры там прописаны непосредственно в коде и отвечают за реализацию наиболее распространённых типов материалов, как физических, так и не очень. К тому же я смутно припоминаю, что там присутствовал даже функционал из Id Tech III - например модуляция цвета по заданным формулам или программная деформация вертексов. Не берусь утверждать что там нельзя подключать собственные шейдеры, т.к. аналогично не имею опыта разработки под этот движок, однако концепция Uber-Shader, на мой взгляд не слишком дружелюбна к пользовательским изменениям. Впрочем, я могу и ошибаться, если вы знаете, как оно на самом деле, вы можете аналогично написать об этом в комментариях.
Unreal Engine 4:
Аналогично, поскольку я не имею опыта разработки под UE4 (пусть вас это не удивляет, я всё же не дизайнер), могу сказать лишь то, что вижу из
документации - пользователю предоставляется большой набор функций, констант и визуальное редактирование. Есть возможность реализации каких-то условий на Blue Prints, опять таки, представленных визуально.
Теперь, собственно, о том, что же именно мне не нравится в вышеперечисленном. Как вы успели заметить, все описываемые концепции объединяет одна и та же идея - код рендеринга по прежнему реализуется в ядре движка, он заточен под строго определённые условия, с небольшой вариативностью и не предполагает сильно иных условий. К тому же к нему в обязательном порядке прилагается набор GPU-шейдеров, которые с высокой долей веростности используется самим движком для тех или иных задач, из чего следует, что пользователь не может полностью менять эту систему по своему усмотрению. Он может лишь адаптироваться к предлагаемому конвейеру и следовать ему, иногда создавая кастомные материалы, в тех пределах, в которых это позволяет функционал движка. Аналогично, если материал предполагает текстовое редактирование, набор ключевых слов определён жестким образом, что налагает определённые ограничения на описание самого материала.
Моя концепция в этом плане всегда была более расширенной. Я пытался рассматривать код рендеринга в движке не как законченную конструкцию со своими законами, а просто как часть абстракции драйвера, реализуюшую те вещи, которые в самом драйвере отсутствуют в силу привязки к конкретным данным, обусловленным архитектурой, непосредственно, движка. Ну например загрузчики текстур, глобальные переменные тех или иных состояний - значений тумана, положения солнца, настроек тех или иных объектов. Эта идея пришла ко мне не сразу, но оформилась постепенно. Когда я осознал её возможности в полной мере, то понял, что уже не смогу от нее отказаться. Суть идеи заключается в том, что пользователь не просто создаёт свои материалы, оставаясь в рамках настроек, предоставленных ему движком, нет, он формирует собственный рендерер, используя лишь вполне конкретные вызовы, влияющие на состояние конвейера рендеринга. Однако при таком подходе любое описание материала превратилось бы в длинную простыню, состоящую из настройки тех или иных состояний, подгрузки шейдеров, установки констант. Для этого был создан мощный инструмент автозамены на базе расширенных макросов, который в свою очередь позволяет дизайнеру сформировать собственный язык описания материалов, сымитировать уже существующий (при условии что он тоже текстовый) или же модифицировать имеющийся. В первую очередь подобный подход позволяет оперативно вносить изменения в уже существующий конвейер, например с целью его перевода на PBR или же наоборот, для формирования максимально простого (old-school) рендеринга, где в процессе используется
всё та же диффузная текстура и световая карта (lightmap). Ядро движка при этом остаётся неизменным и сохраняется сквозная совместимость со всеми будущими версиями. К тому же подход обеспечивает динамическую перезагрузку материалов, например при модификации консольных переменных, что в свою очередь позволяет реализовывать разные типы рендеринга (например для более мощных видеокарт). Аналогично на уровне описания самих материалов присутствует возможность проверки тех или иных расширений, например для использования видеокарт от Intel в упрощенных режимах рендеринга. Но более подробно об этой системе я расскажу уже в следующей заметке.
Продолжение следует.
Я так понимаю, Вы хотите использовать в рендере "data-driven" дизайн. Очень понравился подход такой, недавно примерно такой же видел в движке знакомого, он рендерпассы описывал в json файле. Поэтому назвреает вопрос, а не будет экспонентанциональной усложенения код? И как будет такая система влиять на производительность? Потому что захардкоженный рендер будет в любом случае быстрее.
Chukcha, да, он самый. Код усложняться не будет, потому что он в данном случае описывает только общие случаи поведения, а конкретика задаётся в скриптах. На производительность это никак не повляет, поскольку материалы собираются в инструкции при старте движка. То что захардкоженный рендер быстрее это стереотип, мы же не обращаемся к скриптам во время рендеринга. Наоборот у нас патчи настроенные патчи для рендеринга, без каких-то лишних условий, т.е. это может быть даже быстрее классического кода. Плюс гибкая возможность управлять производительностью прямо из самих скриптов. Опять таки подобный слой абстракции легко позволяет адаптировать рендерер к новому API, например к Вулкану.
Дядя Миша, Планируется ли поддержка вулкана? Если да, то какие идеи по его реализации возможно были? Например, распихать командные буфера по потокам и потом диспатчить это
Chukcha, в самую последнюю очередь, когда конвейер уже будет отлажен. Я им пока принципиально не интерисуюсь, жду когда устаканится.
Go up