Привет.
Я – самопровозглашённый программист графики и indie-разработчик игр. Моё желание и цель – разработка хороших и интересных видеоигр.
Помимо графики я также писал физику, геймплей, тулзы, плагины… и чего только не писал. Главное – было бы ради чего.
Что же я сделал и каков мой пройденный путь?
Жили были я и мой друг (я обязательно оставлю его ник/контакты, как только он решит что мне о нём здесь написать). И хотели мы делать игры. И повелось так, что я писал весь код, а он делал арт. Впрочем, я тоже иногда делаю арт – но об этом позже. Ну и мы начали:
– Так и не завершённый (заморожен до далёких времён) шутер Incident. Изначально был модом на игру Mafia: The City of Lost Heaven. Следует упомянуть, что никаких официальных моддинговых тулз к движку не было – и фанаты изощрялись как могли (и, сложно поверить, изощряются до сих пор). Приходилось реверсить форматы, писать самопальные недоредакторы, конвертеры, мучить файлы в хексе… Наибольший вклад в создание вообще возможностей моддинга тогда внесли такие люди, как GOLOD55, zibob32 и Akay, возможно и другие, кого я незаслуженно забыл. Попачкать руки пришлось и мне – отличительной фишкой тогдашнего Инцидента были лайтмапы – до этого моддеры довольствовались повертексным движковым светом.
Счастливые и безмятежные были времена моддинга. Несмотря на кривость наших недоредакторов, мы всё же могли пользоваться готовым, проверенным движком, который скрывал от нас многие сложности и “просто работал”.
Скриншоты с Mafia-версии:
По сравнению с мафийными модами того времени, картинка у нас была самая понтовая, и ЧСВ так и распирало.
Однако этого нам было мало. Прогресс стремительно двигался вперёд, графика Мафии устаревала (дело было в 2007 году, если память не изменяет), и мы хотели сделать круче. Резко прекратив разработку мода, мы объявили Инцидент отдельной игрой. Вероятно, зря – в виде мода мы бы хотя бы смогли бы его довести до конца.
Тут надо сделать небольшое лирическое отсутпление что бы понять причину такого решения. С детства я интересовался программированием. Моя бабушка была программистом, её брат тоже что-то умел – тут и там валялись книжки от “MS-DOS для пользователя” до “Введение в язык С” (названия пишу по памяти, но смысл верен). ПК в семье был с моего 4х-летнего возраста и много раз менялся по мере моего взросления, однако до 2004 года доступные мне ПК всегда были на несколько лет отстающими от современных. Страстными глазами я смотрел на скриншоты современных игр в журналах и мечтал о них. По большей части, все игры, которыми я располагал были очень скучными и сложными. Я не был одним из тех хардкорных игроков, которые проходили HL1 по несколько раз – я не смог пройти его даже один. У меня просто не было мотивации, уровни были однообразны, а атмосфера неизменно угнетающей. И это уже HL1 – чего уж говорить о поколениях более ранних игр.
В общем, мне нравились игры как сама по себе форма – но до 2000х я не встречал конкретных экземпляров, которые бы вызывали у меня большую симпатию. И т.к. в моём распоряжении был компьютер, на котором каким-то чудом стоял qbasic, несколько книжек и англоязычный хелп этого самого бейсика – я (взяв толстый словарь) начал пытаться непременно делать свои игры, в которых бы всё было как я хочу. За кубейсиком последовал Dark Basic – к моему огорчению, 3D-ускорителя у меня не оказалось, и пришлось довольствоваться 2D. Тогда я сделал свои первые спрайтовые гоночки и недостратегии. Dark Basic сменился Blitz Basic’ом – и в него я влюбился надолго, заодно скорешившись с коммьюнити русских блицеров. Блиц казался менее “казуальным”, и к нему писали множество либ и врапперов – можно было даже пожамкать PhysX.
Будучи долгое время на устаревшем железе, жадно смотрящим в сторону современных игр, и судя о них по скриншотам в журналах (ибо больше не по чему было – ютубы ещё не появились, да и на диалапе много не посмотришь), я восхищался их графикой, и даже нередко её переоценивал – кто там разберёт на маленькой картинке – настоящее отражение или в диффуз впечено? Это мотивировало меня и самому пытаться делать что-то “графичное”, пытаясь извратиться на бедном FFP как только можно (вспомнить хотя бы тормозящее попиксельное искажение на ЦПУ).
В то время (конец 90х, начало 2000х) игры развивались очень быстро – как технологически, так и идейно. Мне казалось, что я стою на пороге некой революции – будто ещё немного, и человечество создаст, наконец, Матрицу. Создание игр приняло для меня облик сотворения миров, такой эпичный и захватывающий, что хотелось быть частью этого.
Поворотным моментом для меня стало появление движка Xors3D – который добавлял в блиц DX9 рендер с шейдерами, от самого упоминания которых я с восхищением дрожал. ШЕЙДЕРЫ! Я люблю, как звучит это слово!
Итак, в моём распоряжении был любительский DX9 движок и, благодаря помощи и примерам Моки, я разобрался в основах HLSL. Помимо этого, благодаря моддингу и сопутствующему реверсингу, я худо-бедно понимал как нормальные люди хранят бинарные данные. Это и было причинами, по которым казалось, что разработка качественной игры вполне себе осуществима.
Наш энтузиазм, на удивление, передавался и другим – немало помогли нам тогда художники Сергей Су и SkyGround.
Что же было дальше? Скриншоты:
Можно даже сказать, что получалось не так плохо. Однако тратили мы на это чертовски много времени – да и на что тратили – вместо того, чтобы делать, собственно игру, мы погрязли в создании графики и, в конце концов, поняли, что в наши уровни невозможно играть. Они, выстраданные, пробегались за пару минут, а продумывание геймплея, по большей части, было упрощено до расставления врагов на равномерном расстоянии по пути игрока. Это не было похоже на глубокое атмосферное приключение в пост-апокалиптическом мире – наш энтузиазм начал иссякать. Диздок был многократно переписан с нуля, и, наконец, проект был заморожен – мы просто не могли потянуть его в то время, или были не столь умны, чтобы сделать его уникальным и интересным и в то же время дешёвым в реализации.
Проект дал мне много опыта – под шквалом падающего в игру контента, необходимо было оптимизировать как пайплайн его засовывания в движок, так и сам рендер. Много пейперов было прочитано.
Результирующим подходом по пайплайну было определение свойств поверхности по её текстуре, причём не только графических но и физических и прочих. К примеру, когда игра загружала модель ящика, она связывала имя его текстуры с одноимённым конфигом, содержащим свойства шейдера ящика (дефайны, константы), физические свойства (трение, масса), звуки (слабый/сильный удар, звук попадания пули), декали (виды дырок от пуль). Вообще, подход был довольно приятен в работе, но, как оказалось, нам периодически хотелось использовать одну и ту же текстуру, но давать объекту разные свойства рендера/физики, и тут система начинала разваливаться – доходило до того, что мы дублировали одинаковые текстуры ради того, чтобы у них были разные имена.
Рендер был сделан в традициях Source – лайтмапы для статики, ambient cubes для динамики; динамические тени от дин. объектов я блюрил в скрин-спейсе и умножал на лайтмапленую картинку. Сцена состояла из множества convex секторов, соединённых порталами – через порталы проводился дополнительный фрустум, который куллил видимый в нём сектор. Шейдеров, кроме постпроцессов, было 2 – для статики и для динамики, но это были толстые убершейдеры, контроллируемые дефайнами.
Впрочем, ФПС все равно не радовал – движок был не слишком оптимизирован, да и за дипами мы плохо следили. Последней каплей стало отсутствие поддержки в движке фоновой загрузки ресурсов – наш контент весил так много, что мы просто обязаны были стримить его по ходу движения игрока, он не влезал в тогдашнюю мелкую видеопамять (у меня было 256 мб).
Ну и тогда я пошёл дальше – надо было непременно перейти на C++ и иметь возможность выбирать разные движки.
Я быстренько поглядел туторы по С++, подключил, для начала, тот же Xors3D и пошёл делать свой игровой движок – по ходу дела допуская все мыслимые и немыслимые ошибки, создавая утечки и рандомные краши. Первый блин – комом!
Движок загружал сцены, сделанные в моём же редакторе, причём большую часть времени я потратил как раз на редактор – теперь мне приходилось не только заботится о работоспобности игры, но и функционале и удобности редактора.
Редактор умел много чего за пределами расставления моделек: создание CSG геометрии и булевые операции с ней, автоматическая развёртка под лайтмапы, интеграция с Beast (не спрашивайте откуда он у нас тогда был), настройка постпроцесса, внутренний скриптовый редактор…
Отдельной гордостью была система партиклов, полностью на GPU:
Однако всё это было сильно сырым и глючным. Кроме того, осознав, что в данный момент мы не потянем большой проект, мы решили испытать это всё в чём-нибудь попроще. Таким образом, наш следующий проект был аркадой про лодочки, которые плавают и стреляют друг в друга.
Графика в этой игре не блистала – были взяты первые попавшиеся под руку модельки и сделано несколько тестовых миссий. В них можно было играть, но крайне скучно. Энтузиазм снова иссяк.
Отчаявшись, мы начали делать приложение для вконтакта – но это не только было невесело делать, но и конкурентов было полно, а за серверы надо платить. Слишком мало гарантий, слишком мало интереса в разработки для соц. сетей. Проект был снова заброшен, не успев толком начаться – разве что успел немного вкурить в AS/PHP/mySQL/VK API.
Где-то в параллели, я продолжал помогать моддингу Мафии, периодически выпуская разные тулзы и небольшие моды. На mafiapub.com (в момент написания поста сайт, увы не работает; но упомянутые штуки можно найти и на других фан-сайтах) можно найти мои импортер/экспортер моделей для макса (на MaxScript) а также мод, добавляющий шейдерную воду (Water Shader Mod), сделанный через жестокий прокси длл между игрой и DX8 (шейдеры 1.0, написаны на асме).
Вообще, стоит отметить, после C++ опыта никакой язык уже не выглядел для меня совсем уж “не родным”. Везде, по большому счёту, одинаковые конструкции, всем правит логика. Так что с того времени я сбился с счёту на каких языках я писал. Когда ты понимаешь основные принципы кодинга и работы компьютера, ты видишь их отражение в любом языке или API.
Тем временем, я был студентом института по киношной специальности. В качестве курсовых мы делали ролики, и один стоит отметить и здесь – т.к. времени на него было угрохано не мало. В плане программирования я делал некоторые помогающие пайплайну скрипты и шейдеры (HLSL для вьюпорта и для mental ray’евские для рендера), но по большей части на мне было всё 3D, монтаж и часть компоуза, а друг был “арт директором” и делал всё 2D.
А вот и сам ролик:
Множество шотов из него было вырезано и так и не дошли до финала из-за того что их просто нельзя было куда-то вставить “в тему”.
Как, например, вот этот кадр с Йоханнесбургом: youtu.be/V3d7PKOejgM
Между тем, Render, автор PhysX враппера для блица и соавтор Xors3D, связал меня с чуваками, занимающимися авиатренажёрами. Перспектива разрабатывать вертолётный симулятор для тренировки пилотов была интересной – с неё можно было получить намного больше опыта (и денег, как предполагалось), чем с клепанья унылых казуалок (чем в большинстве случаев занимаются унылые геймдев стартапы).
Так началась разработка симулятора и самая большая моя прокачка как кодера. Симулятор делался полностью на своём движке (DX9), который переписывался с нуля пару раз. Мой движок наконец поддерживал стриминг. Друг-артист отказался рисовать террейн тайлами и я был вынужден реализовывать мегатекстуры и их стриминг. Мегатекстуры были по началу по заветам Кармака – рисовался специальный пасс, выводящий инфу о необходимых тайлах, анализировался на цпу, и данные подгружались для отрисовки. Однако, гонять текстуру в оперативку было слишком дорого, так же как и позволять лишний пасс при большой геометрической сложности террейна. Т.к. мегатекстуры использовались только для террейна, система была упрощена до квадтри, и определение требуемых тайлов делалось быстро на цпу без участия гпу. Благодаря этому так же и исчезла назойливая черта классических мегатекстур – зависимость от ротации камеры. Можно стало резко поворачиваться во все стороны и не видеть запаздывающих подгрузок.
Движок имел полный набор тулз к нему – экспортер моделей и разные вспомогательные утилиты.
Сама геометрия террейна также была разбита на квадтри с хитрым морфинг в вертексном шейдере для скрытия швов между кусками.
С тенями тоже пришлось повозиться – идея накинуть на всё каскадные провалилась – либо у нас не было теней вдалеке, либо мы теряли качество близких теней, 4х сплитов не хватало чтобы получить хорошее качество везде. Кроме того, флоатовая погрешность не давала нам получить аккуратные тени от мелочей под острым углом (закат) на всей территории. В результате пришлось делать смешанный подход: каскадные тени остались от построек, для террейна – мини гпу рейтрейсер хейтмапы, пересчитывающий лайтмапу террейна только при отклонении солнца на несколько градусов, от вертолёта был отдельный маленький VSM, всегда детальный, а облака рисовались в ещё одну текстуру чёрным по белому без сортировки, которая затем умножающе проецировалась на всё сверху.
Таковые реалии реалтайм рендеринга – или всё выглядит херово и тормозит или ты реализовываешь частные случаи для всего.
Было реализовано ещё до черта всего – от спавна машинок на дорогах и симуляции капель на стекле до динамической смены времени суток и даже года (!).
Не трудно догадаться, что при малом опыте и больших амбициях, разработка затянулась на черезчур долгое время. В результате сроки были упущены, но нам было предложено переделать симулятор из вертолётного в парашютный – на него спрос ещё был, а сложность была ниже.
И началась разработка парашютного: было выпилено всё недоделанное и малонужное (поезда, светофоры, песчаные бури), был взят чуть поменьше масштаб мира и всё стало вылизываться.
Для параштного также был сделан интересный процедурный генератор домов – в результате мы имели тысячи разных и более-менее аккуратных построек на карте.
Результат был довольно неплох:
За это мы даже умудрились получить деньги. И жили бы долго и счастливо, но запланированных массовых продаж не последовало – конкурентные продукты обошли нас в глазах покупателей, и тренажёрные товарищи забили на нас.
Дальше я делал что-то по мелочам.
Например, вот эту реалтайм бутылочку:
Тут я в шейдере симулировал движение всех лучей отражённых/искажённых и проходящих сквозь стекло. Целью было приблизить качество к рейтрейсеру. Вроде что-то получилось:
Ещё я делал radiosity лайтмаппер на GPU:
Но он вышел слишком медленным, чтобы его юзать. Зато он считал GI! Это было весело.
Таким образом проведя ещё одно лето, я внезапно столкнулся с тем, что оканчиваю институт – и пора бы мне делать диплом. И решил я делать диплом о том, о чём больше знал – о реалтайм рендеринге.
Но об этом напишу в следующем посте. Сейчас пора спать.
Вот такой я у мамы молодец.