Одна картинка -шедевр, сто картинок -катастрофа: как я пытался укротить AI-генерацию ассетов для инди-RPG

Разработка инди-игры - это постоянная борьба с ресурсами. Обычно не хватает времени, денег, людей и, желательно, ещё пары часов в сутках.
Когда я начал делать Morveyn (https://habr.com/ru/articles/1100432/)- пошаговую RPG для Telegram, вдохновлённую классическими фэнтезийными стратегиями вроде King's Bounty, - довольно быстро выяснилось, что написать игру и наполнить её контентом - две совершенно разные задачи.
С технической частью всё было относительно понятно: Next.js на фронтенде, Java на бэкенде, игровая логика, взаимодействие с сервером, генерация карты. Это привычная территория разработчика.
А вот графика оказалась отдельным приключением.
Игре нужны десятки, а в перспективе сотни изображений: юниты, портреты персонажей, здания, объекты окружения, тайлы глобальной карты, иконки и элементы интерфейса. Причём всё это должно выглядеть так, будто создано одним художником для одной игры.
Нанимать художника для каждого экспериментального ассета на стадии MVP было нерационально. Поэтому я решил попробовать генеративный AI.
В итоге основным инструментом стал Gemini.
И тут началось самое интересное.
Одна красивая картинка - ещё не победа
Сгенерировать красивого фэнтезийного рыцаря сегодня несложно. Достаточно описать, что хочется увидеть, добавить пару стилистических ориентиров и можно получить вполне впечатляющий результат.
Проблема начинается, когда после рыцаря тебе нужен гоблин-шаман. А после него - скелет-воин, эльфийский лучник, башня, лесной объект и иконка способности.
Каждая отдельная генерация может выглядеть отлично. Но если поставить все результаты рядом, внезапно выясняется, что они словно из разных игр. Так еще и накладываются друг на друга

Один персонаж выглядит как иллюстрация из настольной RPG. Второй - как современный 3D-рендер. Третий напоминает концепт-арт для дорогой компьютерной игры. Четвёртый вообще похож на детскую книжную иллюстрацию.
По отдельности красиво. Вместе - визуальная катастрофа.
Именно здесь я понял, что проблема генерации игровых ассетов заключается не столько в качестве отдельных изображений, сколько в контроле над вариативностью.
Игровой ассет должен быть не просто красивым. Он должен соответствовать определённым требованиям:
иметь предсказуемый ракурс;
занимать примерно одинаковую площадь изображения;
сохранять визуальный стиль;
хорошо читаться в небольшом размере;
не содержать случайных декоративных элементов;
сочетаться с остальными объектами игры.
По сути, мне понадобилась не нейросеть, которая умеет рисовать красивые картинки, а инструмент, способный соблюдать визуальную спецификацию.
Звучит знакомо для разработчика, не так ли?

Промптинг как программирование
Мой первый подход был довольно наивным: описывать каждый объект отдельно.
«Нарисуй гоблина-шамана в стиле старой фэнтезийной RPG».
Затем:
«Нарисуй скелета-воина в стиле старой фэнтезийной RPG».
Проблема в том, что одинаковая формулировка не гарантирует одинаковой интерпретации. Модель каждый раз заново принимает множество творческих решений.
В какой-то момент я решил изменить подход.
Вместо того чтобы каждый раз писать новый запрос, я разделил промпт на постоянную и переменную части.
Условно:
Базовая часть - визуальная спецификация:
painterly digital illustration;
стиль классических фэнтезийных стратегий 1990-х;
богатая текстура масляной живописи;
тёплый золотистый свет сверху слева;
приглушённая земляная палитра;
тёмно-коричневые оттенки дерева и акценты старого золота;
единая визуальная стилистика игрового мира;
никаких надписей, логотипов и водяных знаков.
Переменная часть - конкретный объект:
гоблин-шаман с деревянным посохом;
скелет-воин с ржавым мечом;
эльфийский лучник с длинным луком;
каменная башня с красным флагом.
В результате каждый новый запрос стал похож на вызов функции с параметром:
generateAsset( style = COMMON_STYLE, subject = "Goblin Shaman", constraints = COMMON_RULES
);Конечно, Gemini не исполняет такой код буквально. Но сама инженерная модель мышления оказалась полезной.
Я перестал воспринимать каждый промпт как отдельное произведение искусства и начал относиться к нему как к конфигурации генератора.
В моём случае это вылилось в отдельные общие блоки для разных типов изображений. Например, портреты персонажей и объекты глобальной карты получили разные описания стиля и композиции.
Для портретов важны положение персонажа по грудь, вид в три четверти, запас пространства над головой и спокойный размытый фон.
Для карты требования другие: единый угол обзора, одинаковый масштаб объектов, ортографическая проекция без перспективных искажений и тёплый свет сверху слева.
Это важное различие. Один универсальный промпт на всю игру оказался бы слишком абстрактным. Гораздо практичнее иметь общие правила для каждой категории ассетов.
Такой подход не сделал результаты абсолютно одинаковыми, но значительно упростил контроль над стилем.
Самая недооценённая часть промпта - то, что нельзя рисовать
Когда мы составляем запрос для генерации изображения, обычно концентрируемся на том, что хотим получить.
Но для игровых ассетов не менее важно определить, чего мы категорически не хотим видеть.
Генеративные модели любят украшать изображения. Им хочется добавить красивое освещение, объёмные тени, атмосферную дымку, отражения и дополнительные декоративные элементы.
Для отдельной иллюстрации это может быть преимуществом.
Для игрового объекта, который должен помещаться в клетку карты размером несколько десятков пикселей, это скорее проблема.
Представим, что нам нужен простой юнит для тактической RPG.
Вместо компактного персонажа мы получаем:
драматическое кинематографическое освещение;
сложную перспективу;
глубокие тени;
частицы и магические эффекты;
детализированный фон;
декоративные элементы, которые начинают сливаться после уменьшения изображения.
В результате персонаж выглядит впечатляюще на большом экране, но превращается в нечитаемое пятно в самой игре.
Именно поэтому я начал уделять особое внимание отрицательным ограничениям.
В Stable Diffusion для этого существует отдельное поле Negative Prompt. В Gemini я использовал другой подход: формулировал запреты и ограничения непосредственно в текстовой инструкции.
Например, для игровых объектов можно использовать следующий шаблон:
Create a 2D fantasy RPG game asset.
The character must have:
- a clear silhouette;
- simple readable shapes;
- consistent visual style;
- controlled composition;
- minimal unnecessary details.
Avoid:
- photorealism;
- 3D rendering;
- anime and cartoon styles;
- modern objects;
- blurry details;
- text and watermarks;
- unnecessary frames and borders;
- distorted anatomy;
- cropped heads.
The character must remain clearly recognizable
when displayed at a small game resolution.Разумеется, ограничения нужно адаптировать под конкретную категорию изображения. Например, для Morveyn я не хотел полностью убирать сложные фоны из портретов и сюжетных сцен. Там они, наоборот, помогают передать атмосферу мира.
А вот для отдельных объектов глобальной карты подход оказался другим. Мне нужны были изолированные деревья, города и замки, которые можно разместить на клетках карты.
Поэтому для них я использовал отдельную композиционную инструкцию и ярко-розовый фон #FF00FF, который можно удалить при постобработке.
На первый взгляд всё это выглядит как чрезмерное количество ограничений.
Но в этом и заключается смысл.
Хороший промпт не только объясняет модели, что нужно нарисовать. Он ограничивает пространство решений, которые модель может принять самостоятельно.
Особенно важно это для объектов, которые будут отображаться в небольшом размере.
В таких условиях читаемость силуэта зачастую важнее количества деталей.
Композиция: когда хороший арт не подходит игре
Следующая проблема оказалась менее очевидной.
Даже если Gemini генерирует объекты в похожем стиле, они могут совершенно по-разному располагаться внутри изображения.
Один персонаж занимает почти весь холст. Другой оставляет вокруг себя огромное пустое пространство. Третий обрезан по ногам. Четвёртый изображён под совершенно другим углом.
Для обычной иллюстрации это не проблема.
Для игрового ассета - проблема серьёзная.
Особенно если изображения должны использоваться в интерфейсе, на карте или в одном наборе юнитов.
Поэтому я начал отдельно фиксировать композиционные требования:
объект располагается по центру;
персонаж полностью помещается в границы изображения;
используется одинаковый масштаб;
сохраняется единый угол обзора;
не добавляются случайные элементы вокруг объекта;
фон соответствует требованиям конкретного типа ассета.
Для объектов карты я пошёл дальше. В промптах отдельно указывал, что объект должен занимать около 80% ширины изображения, основание должно располагаться внизу по центру, а вокруг не должно быть дополнительной поверхности земли.
Это помогает размещать разные объекты на карте без ощущения, что один замок в два раза крупнее другого только потому, что модель выбрала для него другую композицию.
Кроме того, для всех объектов карты я зафиксировал общий ракурс: вид сверху под углом примерно 60 градусов. При этом у зданий должны быть видны и крыши, и передние стены.
Если дерево изображено почти сбоку, а замок строго сверху, они уже не выглядят частями одной игровой карты.
Это кажется мелочью, пока не начинаешь собирать десятки изображений в одну систему.
Тогда становится понятно, что единый стиль - это не только одинаковая палитра и толщина линий. Это ещё и единые правила композиции.
Фон, прозрачность и прочие неприятности
Отдельная история - фон.
Когда генерируешь игровые объекты, очень хочется сразу получить PNG с прозрачностью и просто положить его в игру.
Но генеративная модель не всегда понимает прозрачность так, как её понимает графический редактор.
Иногда вместо настоящего альфа-канала получается шахматный фон, который лишь имитирует прозрачность. Иногда фон имеет почти однородный цвет, но вокруг персонажа остаются цветные ореолы. Иногда появляются дополнительные тени или элементы окружения, которые сложно удалить автоматически.
Поэтому я старался разделять две задачи:
Получить хороший объект с контролируемой композицией.
Подготовить изображение для использования в игре.
Для второго этапа можно использовать отдельную обработку:
удаление фона;
создание альфа-канала;
обрезку изображения по границам объекта;
нормализацию размеров;
приведение изображений к единому формату.
Для объектов карты я выбрал простой практический подход: генерировать их на ярко-розовом фоне. Его легче удалить программно, чем пытаться автоматически отличить все оттенки фона от деталей самого объекта.
Это особенно удобно для деревьев, замков и других объектов, в которых встречаются зелёные, коричневые и серые оттенки. Розовый цвет практически не пересекается с их естественной палитрой.
Для текстур земли, воды и дорог, наоборот, фон не нужен. Там я использовал отдельные промпты для бесшовных текстур с равномерным освещением и без объектов или теней.
Это важный момент: не нужно пытаться решить все задачи одним запросом к нейросети.
Генерация изображения и подготовка игрового ассета - разные этапы пайплайна.
Если результат генерации хороший, но фон мешает его использовать, это ещё не повод выбрасывать изображение.
Референсы: иногда лучше показать, чем объяснять
Ещё один полезный приём - использование уже готовых изображений в качестве референсов.
Не всегда, но в некоторых случаях это значительно упрощает работу.
Например, можно долго объяснять модели, каким должен быть ракурс персонажа, или показать изображение, композиция которого тебя устраивает.
Я периодически использовал такой подход, когда текстового описания было недостаточно.
В Morveyn я также предусмотрел создание эталонных изображений, которые можно использовать для дальнейших генераций.
Например, сначала можно сгенерировать несколько вариантов портрета Эдрика, выбрать лучший и использовать его как образец стиля для остальных персонажей.

А для объектов глобальной карты полезным референсом стал удачный вариант замка Морвейна. На его основе проще выдерживать масштаб, угол обзора, освещение и характер детализации других зданий.
Однако здесь есть нюанс: референс может повлиять не только на нужную композицию, но и на другие характеристики изображения.
Модель может перенести нежелательные детали, изменить цветовую палитру или слишком буквально повторить исходный объект.
Поэтому важно формулировать, что именно нужно взять из референса:
композицию;
ракурс;
пропорции;
расположение объекта;
общий визуальный язык.
И отдельно указывать, что должно остаться уникальным.
Например, если референс нужен только для композиции, не стоит просить модель просто «сделать похожую картинку». Лучше явно обозначить, что расположение и масштаб нужно сохранить, а персонажа и его детали заменить.
Почему сотни ассетов - это отдельная инженерная задача
Когда речь идёт об одном изображении, можно позволить себе десяток итераций и выбрать лучший результат.
Но когда нужно подготовить несколько десятков юнитов, десятки объектов окружения, здания, портреты и элементы интерфейса, ручной подход начинает плохо масштабироваться.
Возникает несколько проблем.
1. Непредсказуемость.
Даже при одинаковой структуре промпта результат может отличаться по композиции, деталям и визуальному исполнению.
2. Непоследовательность.
Через некоторое время начинаешь замечать, что новые изображения немного отличаются от старых. И приходится возвращаться к предыдущим ассетам или корректировать новые.
3. Контроль качества.
Нельзя просто принять все результаты генерации. Каждый ассет нужно проверить в контексте самой игры, а не только оценить отдельно.
4. Постобработка.
Удаление фона, обрезка, масштабирование и подготовка файлов могут занять не меньше времени, чем сама генерация.
5. Накопление визуального долга.
Если принимать каждый красивый результат без проверки соответствия общему стилю, через некоторое время придётся переделывать целые группы изображений.
В этом смысле работа с AI-графикой оказалась удивительно похожа на разработку программного обеспечения.
Можно быстро написать несколько классов, но поддерживать большую систему без общих правил, контрактов и проверок гораздо сложнее.
Поэтому я начал рассматривать набор промптов не просто как коллекцию текстовых запросов, а как часть технической документации проекта.
У каждого ассета есть имя файла, назначение, размер, требования к композиции и описание того, что должно оказаться на изображении.
Это позволяет не только генерировать графику, но и связывать её с конкретными элементами игры.
Например, tree_oak.png - это не просто картинка дуба. Это объект карты с определёнными требованиями к масштабу, фону, ракурсу и расположению основания.
А portrait_knight.png - портрет конкретного героя, внешний вид которого должен совпадать с его фигуркой в бою.
Чем больше становится проект, тем полезнее такая структура.
Мои Best Practices
По итогам экспериментов я сформировал для себя несколько правил, которые заметно упрощают работу.
1. Сначала определить визуальный стиль, потом генерировать контент.
Не стоит начинать с генерации сотни случайных объектов. Сначала нужно добиться нескольких эталонных изображений, которые будут определять внешний вид всей игры.
2. Разделять постоянные и переменные части промпта.
Стиль, освещение, палитра, композиция и ограничения должны быть максимально стабильными. Меняться должен прежде всего сам объект.
При этом для портретов, сцен, текстур и объектов карты лучше иметь отдельные блоки правил.
3. Не забывать про отрицательные ограничения.
Указывать, что нельзя добавлять, иногда не менее важно, чем описывать желаемый результат. Особенно это касается нежелательных визуальных стилей, перспективных искажений, сложного освещения, фонов и лишнего декора.
4. Проверять результат в реальном игровом размере.
Картинка может выглядеть великолепно в разрешении 1024×1024, но оказаться совершенно бесполезной после уменьшения до 64×64.
5. Разделять генерацию и постобработку.
Не нужно заставлять AI одновременно рисовать объект, удалять фон, подгонять размеры и готовить финальный PNG.
6. Использовать референсы для сложной композиции.
Если важен конкретный ракурс или расположение объекта, иногда проще показать пример, чем пытаться описать всё словами.
7. Не принимать каждый красивый результат.
Главный критерий - не художественная ценность отдельной картинки, а то, насколько хорошо она вписывается в общую визуальную систему игры.
8. Фиксировать требования к каждому ассету.
Указывать имя файла, назначение, размер, тип фона и правила композиции. Это особенно важно, когда графика создаётся в несколько этапов или возвращаться к ней приходится спустя недели.
9. Генерировать несколько вариантов и выбирать лучший.
Не всегда удаётся получить подходящий результат с первой попытки. Для объектов карты я использовал подход с тремя-четырьмя вариантами каждого изображения, чтобы выбрать тот, который лучше сочетается с остальными элементами.
10. Проверять условия коммерческого использования.
Если игра планируется к публикации и монетизации, важно заранее проверить лицензионные условия выбранного сервиса генерации.
Вместо заключения
Работая над Morveyn, я постепенно пришёл к интересному выводу: генеративный AI снимает часть работы с художника, но не снимает с разработчика ответственность за визуальную целостность продукта.
Можно получить впечатляющую иллюстрацию за минуту. Но построить на её основе целую игровую вселенную - совершенно другая задача.
Нужно определить правила, зафиксировать стиль, научиться ограничивать фантазию модели, контролировать композицию и организовать обработку результатов.
И, пожалуй, самое важное - перестать воспринимать AI как волшебную кнопку.
Для меня Gemini стал ещё одним инструментом в разработке Morveyn. Довольно мощным, иногда непредсказуемым, но особенно полезным тогда, когда к нему подходишь не как к генератору случайных картинок, а как к части производственного процесса.
Впереди у Morveyn ещё много контента. А значит, эксперименты с генерацией ассетов продолжатся.
И, судя по всему, вопрос о том, как заставить нейросеть нарисовать ровно то, что тебе нужно, ещё долго будет актуален.
А как вы решаете проблему визуальной консистентности при использовании AI-генерации? Есть ли у вас собственные приёмы, которые позволяют получать десятки и сотни изображений в едином стиле?
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.