Написание редактора шейдеров.
Автор: Justin
Мысли о написании редактора шейдеров.
8<-------
Маленькое вступление.
Часть первая, о том, как планировалось.
Часть вторая, о том, что получилось.
Маленькое вступление.
Данную статью стоит рассматривать в первую очередь, как опыт человека попытавшегося зайти в геймдев окольной и более близкой ему дорогой. Многое из сказанного может показаться смешным умудренным опытам гуру, и всё же статья эта не для них. Статья эта адресована всем тем, кто хочет попробовать свои силы в чём-то новом, но при этом не повторить чужие ошибки, да и просто посмотреть на ход мыслей человека взявшегося за дело ему до этого мало знакомое.
Часть первая, о том, как планировалось.
Уважаемый читатель, не замечал ли ты, что первым делом любой начинающий игроделец ставит перед собой задачу написать самый лучший и совершенный engine. И хотя изобретение очередного велосипеда, безусловно, несёт огромный опыт и возможность пощупать руками всё то, что позволяет появляться на экране картинам различной красоты, мало кому удаётся с первого раза грамотно спроектировать и, главное, закончить своё творение. И сколько примеров ужасно сделанных, либо заброшенных на полпути Франкенштейнов можно вспомнить?..
Такие мысли бродили в моей голове, когда в ней впервые возникло желание окунуться в мир игродева. Стоит ли мне тягаться с монстрами вроде Ogre, не говоря уже о серьёзных коммерческих “движках”? Нет, меньше всего хотелось мне хотелось пополнить ряды забросивших свои проекты программистов. И тут в голову пришла прекрасная по моему личному мнению мысль – ведь игры, это не только быстрое и современное графическое ядро, не только качественный арт, но и то, что лежит в основе всего этого, а именно легко интегрируемый и удобный тулсет.
Что же востребовано в современной игровой индустрии? Очевидно то, что используется везде и всегда, а именно шейдеры. В стане DirectX ловить явно нечего, т.к. против FX composer'a бороться малореально, а вот реализовать что-то подобное для OpenGL — стоит попытаться! Итак, задача понятна, написать собственный RenderMonkey, но быстрее, лучше сильнее. :)
Оправдан ли такой велосипед? Для себя я дал положительный ответ, слишком ограниченным и требующим лишней работы над шейдерами для интеграции их в дальнейшем, показался этот флагман GLSL разработки.
Итак, прежде чем садиться за написание кода, надо было продумать основные черты будущего проекта (и, как показала практика, тактика посидеть и подумать не раз помогала сэкономить в будущем много времени, которое могло бы быть потрачено на переделку).
Во-первых, будущая IDE должна быть легко интегрируемой в процесс разработки сторонних, простите за тавтологию, разработчиков.
Во-вторых, количество кода, не относящегося напрямую к решаемой задаче, хотелось бы свести к минимуму.
В-третьих, хотелось бы вести разработку быстро и отзывчиво.
В-четвёртых, так как это не игровой движок, то можно не слишком акцентировать внимание на вопросах кросс-платформенности и сумасшедшей оптимизации.
Ну, и в-пятых, будущее приложение должно быть функциональнее, чем уже существующие аналоги и иметь свои особые фишки.
Учитывая эти критерии, была выбрана связка CodeGear Delphi + GLScene. Тут, уважаемый читатель, на твоём лице может появиться снисходительная улыбка. Я понимаю тебя, толпы поленившихся элементарно почитать любую книгу по введению в OpenGL подростков, штурмующих форумы с вопросами достойных худших кошмаров разработчика, могут довести любого. Что ж, низкий входной уровень этой связки не всегда приносит лишь положительные плоды. И всё же, откинув предрассудки, посмотрим правде в глаза. BDS – удобная и отвечающая современным стандартам RAD IDE. GLScene, несмотря на многие свои недостатки – хороший и проверенный временем фрэймворк, требующий местами допилки крупным напильником, но при этом позволяющий в любой момент заменить часть себя собственными сколько угодно низкоуровневым кодом, использую при этом все остальные элементы. (Так, в частности, в проекте используется собственный код отрисовки мешей).
Итак, основной задачей, на начальном этапе встал вопрос прозрачного обмена данными между редактором и конечным продуктом. Написать редактор, не имеющий никакой связи кроме банального копипэйста, или же использовании монстроузного формата хранения, как это реализовано в RenderMonkey совершенно не хотелось, идеология FX файлов, казалась более удачной, и всё же недостаточной. Именно поэтому было принято решение, позволить разработчику решить как будет представлена информация, а каким образом она будет хранится, путём подключения ресурсных плагинов. Такой плагин является промежуточным слоем при общении RF с внешним миром на этапе загрузки и сохранения. Плагин получает и отдаёт информацию в одном из широко распространённых форматов:
XML — для передачи информации о структуре пайплайна, свойствах отдельных объектов, иерархии объектов, а также настройках проекта.
Тут стоить заметить, что писать собственные XML велосипеды совершенно не хотелось, и был выбран вариант сериализации, для чего пришлось обратиться в библиотеке JEDI. Доступный в ней сериализатор хоть и оказался уже неподдерживаемым, и местами написанным не самым лучшим способом, но с другой стороны, полностью справлялся со своими задачами и позволял сериализовать не только специально подготовленные для него классы, но также классы GLScene, что позволило сохранять информацию о свойствах объектов без лишних затрат.
TXT – для кода шейдеров.
3DS – для геометрии мешей.
PNG – для текстур. Плагин может по своему желанию сообщить, что хочет принимать текстуры в TGA формате.
BIN – для масок видимости фэйсгруп мешей. О масках видимости речь ещё пойдёт далее, формат для их хранения совершенно прост и представляет собой набор записанных подряд булевых значений, с их общим числом в самом начале файла.
Ресурсный плагин, волен проигнорировать ненужную ему информацию, к примеру, не сохраняя меши. При этом получаемая информация может быть преобразована в используемые внутреигровые форматы. Так описание сцены может быть преобразовано в собственный формат XML, текстуры преобразованы в DDS и созданы мипмапы. И самое главное, ресурсы могут быть сохранены в виде удобной для дальнейшей прямой загрузки в “движок”, к примеру, запакованы в PAK файл.
Разумным при этом является хранение данных во время активной работы в простом, не требующем сложных преобразований или запаковки формате, к примеру, с помощью плагина реализующего простое склеивание ресурсных потоков и последующее их получение по имени (данный плагин используется по умолчанию), а при подготовке ресурсов к непосредственной интеграции – сохранять в требуемом движку виде. Специально для этого в ходе разработки был добавлен консольный интерфейс пересохранения проектов, специально для batch преобразований.
Следующей, менее масштабной, но не менее важной проблемой стал вопрос о передачи исходных параметров шейдерам. Во-первых, оказалось, что GLScene не имеет поддержки FBO, а только pbuffer’а и копирования текстур. Во-вторых, сама шейдерная подсистема написана совершенно неподходящим образом. Факт этот огорчил меня, и несколько последующих дней пришлось провести за написанием классов реализующих необходимый функционал. За время разработки это была основная заминка, и, пожалуй, единственный момент, когда разработка упёрлась в ограничение фрэймворка.
Вопрос передачи переменных в шейдер оказался не таким простым, как это казалось сначала. Вполне логичным является передача float числа в шейдер float переменной. Но лишь до тех пор, пока число этих переменных не слишком велико. Разработчик движка вполне законно может решить передавать их, компонуя, к примеру, в vec3. Это потребовало добавить в редактор возможность создавать собственные компоновки переменных наряду с уже заготовленными переменными. Тут стоит заметить, что заготовленные переменные (к которым можно отнести, к примеру, синус от времени) тоже могут быть расширены плагинами. Всё это сделано для того, чтобы шейдер содержащийся в проекте мог быть подключён в дальнейшем без изменения его кода.
Ознакомиться со структурой приложения в графическом представлении можно на нижеследующем рисунке.
Рис. 1
19 октября 2007
Комментарии [7]