Улучшаем промо-арты: переход из Unity в Blender

Меня зовут Рамиль Роозилехт, работаю старшим техническим художником в CM Games. В этой статье расскажу, как обновлял технический пайплайн по созданию промо-артов для гоночной игры Nitro Nation. Спойлер: через переход из Unity в Blender.

Новый инструментарий позволил нашей арт-команде сильно улучшить визуальную часть промо-материалов, а их создание теперь происходит заметно быстрее. Для сравнения:

image7.png

Старый пайплайн работы

Раньше создавал промо-арты из скриншотов, сделанных в Unity. Мобильные шейдеры и простое освещение выглядели приемлемо на экране телефона, но плохо подходили для основы промо-материалов.

Например, сцена с запеченным светом в Unity. Если что-то меняется, нужно ждать, пока освещение пересчитывается.

image1.png

Промо после драфтовой дорисовки вручную.

image6.png

Минусы старого подхода:
  • Долго заниматься дорисовкой и фотобашингом поверх отснятых скриншотов. В среднем художник мог сделать не более 1,5 картинок за день.
  • Дорисованный материал часто выглядел хуже, чем арты более новых проектов у конкурентов.

image15.png

  • Невозможно вносить серьезные правки после начала дорисовки. Если в последний момент понадобится что-то изменить, сделать это будет непросто.
  • Сложно передавать исходники сцен. Если переиспользовать старую сцену для новых промо, то надо хранить её в основном репозитории проекта или делать экспорт всех мешей, материалов, текстур и сопутствующих элементов в Unity Package. Каждый объект в свою очередь тянет за собой скрипты, внешние плагины и другие зависимости, которые муторно отключать вручную.

Поиск альтернатив

Вначале собрался доработать существующий процесс съёмки материала. Добавил стандартный package для пост-эффектов Unity Post-Processing Stack. Благодаря нему можно применять пост-эффекты в эдиторе без запуска игры. Далее заменил оптимизированные мобильные шейдера на стандартные PBR материалы, чтобы получить улучшенную модель шейдинга и полный пакет текстур.

Эти изменения немного улучшили картинку, но собирать сцену стало дольше, ведь теперь нужно настраивать измененные материалы и перезапекать освещение. Также, часть эффектов из Post-Processing Stack, например, AO и SSR требовали deferred рендеринга и не были совместимы с forward рендерингом без дополнительной работы.

Чтобы продолжать улучшения, нужно создавать отдельную ветку проекта и в ней глобально менять устаревший рендеринг. Далее потребовалось бы постоянно поддерживать ветку актуальными изменениями из мастера и править конфликты, на что пришлось бы затрачивать дополнительное время. То есть, художники не смогли бы работать с инструментами автономно, потребовалась бы поддержка. Поэтому такой подход будет недееспособным.

Открытая задача: выстроить процесс с ориентированием на художников и их софте. В идеале для этого нужен популярный, бесплатный 3D пакет с продвинутыми возможностями рендеринга. Основные варианты:
  • Unreal Engine. Есть только рендеринг, нужно искать готовые ассеты для сцен.
  • SketchUP. Есть только моделлинг, нужен плагин для рендеринга.
  • Blender. Полный пакет для создания контента.
Преимущества Blender над конкурентами:
  • Полностью бесплатный. У 2D художников обычно нет лицензий на Maya/3dsMax.
  • Open Source и задокументированный API. Большой простор для скриптинга.
  • Постоянные апдейты и улучшения. Одно из самых активных FOSS коммьюнити (улучшают продукт и добавляют свой контент).
  • Легковесность. Инсталлер <200мб, возможность портативного использования, поддержка Windows/Mac/Linux.

Осталось разобраться с импортом и экспортом для сторонних программ. В моем случае понадобится перенести модели вместе с текстурами, сохранив детали в необходимой конфигурации. Машины должны быть максимально похожи на реальные аналоги.

Исходники машин лежат в проекте как FBX’ы и хранят полный набор деталей авто в разобранном виде. Использовать эти файлы для рендеров неудобно, потому что нужно вручную собирать машину из частей. Но машина в игре уже собрана и готова к использованию, нужно только сохранить её. Для этого добавил пакет FBX Exporter в проект. Он поддерживает Binary/ASCII FBX форматы, его можно вызвать в скрипте или использовать из эдитора. Созданные им FBX’ы сохраняют оригинальные ссылки на текстуры и иерархию префаба.

С моделями разобрались, импортируем в Blender. Сейчас машина выглядит даже хуже, чем в игре, ведь FBX не передает полные параметры материалов, особенно когда используются кастомные шейдеры.

Машина сразу после импорта без материалов и текстур. В таком виде не получится использовать её для промо.

image11.png

Чтобы привести машину на скриншоте в презентабельный вид, надо:
  1. Настроить альфу для текстур. На скриншоте видны прозрачные шины и сетка радиатора. В части текстур альфа канал не используется, в других — может использоваться как альфа или как карта свечения. Blender смотрит на формат текстуры при импорте, и если альфа-канал существует, то автоматически подключает его к шейдеру. На самом же деле альфа в качестве прозрачности используется только у лейблов, а с остальных текстур её нужно отключить.
  2. Создать новые материалы. При импорте оригинальные материалы теряют свои настройки, поэтому нужно сделать их альтернативы на shading nodes. Список материалов стандартный, например, авто-краска, резина, хром, пластик, стекло.
  3. Применить новые материалы на все элементы машины. Большая часть элементов машин содержит название материала в именах, так что тут достаточно выбрать все одинаковые элементы и назначить им материал.
  4. Почистить мусор в иерархии. Нужна лишь геометрия и базовая иерархия, всё остальное можно убрать, чтобы упростить навигацию.
  5. Проверить на соответствие с моделькой в игре.

Звучит как огромная трата времени, особенно если делать вручную ежедневно.
Но используя Python API для скриптинга, можно автоматизировать процесс конвертации машины. Тогда художнику останется лишь проверить результат на соответствие с игрой.

Работа со скриптами в Blender

image10.pngСверяюсь с документацией по API, чтобы не писать код вслепую. Скрипты для Blender можно писать прямо в самом файле. Для работы со скриптами доступно 3 редактора:

  • Python Console. Простая консоль с авто-заполнением команд по нажатию на Tab. Полезно, чтобы посмотреть синтаксис команд.
  • Info. Лог, где большинство действий пользователя отображаются в качестве Python команд. Получившийся код можно строками скопировать в скрипты.
  • Text Editor. Встроенный блокнот, из которого можно запускать скрипты и паковать текст прямо внутри .blend файла. В нём также доступны шаблоны для многих скриптов и аддонов. image2.pngНапример, батч-экспорт объектов, UI для создания кнопок\панелей\меню и новых операторов. Запустить открытый скрипт можно по кнопке Play ▶.

Создание аддона для автоматизации импорта авто

Для примера покажу функции, которые использую в аддоне для автоматизации импорта. Функционал такого аддона:
  • Удалить ненужные объекты
  • Загрузить библиотеку материалов, которая запакована в аддон
  • Заменить текущие материалы машина на материалы из библиотеки
  • Выставить корректные значения альфа-канала для текстур
  • Призвать риг водителя

Импорт коллекции из внешнего .blend файла, который упакован внутри аддона:

def importColl(collectionName):

В хедере скрипта должен быть import os, чтобы получить директорию файла

    path=os.path.dirname(__file__) + "/collections/library.blend\\Collection\\"
    bpy.ops.wm.append(filename=collectionName, directory=path)

Удаление лишних объектов из иерархии:

def cleanUp():

List для поиска названий объектов под удаление:

    RemoveStrings = ["Gear*","*flare*","UI*"]

Если выделен объект, снимаю выделение, чтобы не удалить лишнего:

    if  bpy.context.view_layer.objects.active != None:
        bpy.context.active_object.select_set(False)
    bpy.ops.object.select_all(action='DESELECT')

Пробегаю по списку, выделяю объекты и удаляю их.

    for str in RemoveStrings:
        bpy.ops.object.select_pattern(pattern=str)
        print (str)
    bpy.ops.object.delete(use_global=False)
    bpy.ops.object.select_all(action='DESELECT')

Функция для фикса параметров в существующих материалах:

def fixImport():

Всем текстурам, кроме швов, выставляю режим альфа-канала:

    for tex in bpy.data.images:
        if "seamTex" not in tex.name:
            tex.alpha_mode = 'CHANNEL_PACKED'
    for mat in bpy.data.materials:
        if 'Seam' in mat.name:
            continue

Материалам дисков и шин меняю значения metallic, roughness, specular

        if 'Disk' in mat.name:
            mat.node_tree.nodes["Principled BSDF"].inputs[6].default_value = 1
            mat.node_tree.nodes["Principled BSDF"].inputs[9].default_value = 0.25
        if 'tyre' in mat.name:
            mat.node_tree.nodes["Principled BSDF"].inputs[7].default_value = 0.25
            mat.node_tree.nodes["Principled BSDF"].inputs[9].default_value = 1

Для лейблов на машине выставляю Alpha Clip, остальным текстурам обрубаю линк ноды с текстурой, которая автоматически назначается в альфу шейдера.

        if 'ables' in mat.name:
            mat.blend_method = 'CLIP'
            print (mat.name," set to clip")
            mat.use_nodes = True
            mat_node = mat.node_tree.nodes
        else:
            mat.use_nodes = True
            mat_node = mat.node_tree.nodes
            for node in mat_node:
                if "Image Texture" in node.name and node.outputs[1].links != None:
                    for link in node.outputs[1].links:
                        mat.node_tree.links.remove(link)
if mat.blend_method == 'BLEND':
            if mat.name not in ['Glass', 'Glass_Clear']:
                mat.blend_method = 'OPAQUE'

Функция для замены оригинального материала на материал из библиотеки, которая импортируется в начале и содержит необходимые для ссылки объекты. Запакована в try/except pass, чтобы скрипт не падал, если не найдется нужного объекта.

Например, если на машине не будет хрома или карбона.

def applyMaterial(objectName,searchPattern):
   try:
        source = bpy.context.scene.objects[objectName]
        bpy.context.view_layer.objects.active = source
        source.select_set(True)
        bpy.ops.object.select_pattern(pattern=searchPattern)
        for ob in bpy.context.selected_objects:
            if "able" in ob.name:
                ob.select_set(False)
        bpy.ops.object.make_links_data(type='MATERIAL')
        bpy.ops.object.select_all(action='DESELECT')
    except:

Но если действительно не нашлось объектов, можно увидеть в консоли

        print(objectName,"- failed.")
        pass

image5.pngОстальная часть скрипта состоит из вызова перечисленных функций и кода интерфейса для аддона. После его установки, добавится новая панель с кнопками. Дополнительно, я добавил в библиотеку материалов риг гонщика, чтобы импортировать его в любой файл и сажать за руль авто или использовать как референс для масштаба при моделировании окружения.



Создание промо-арта по новому пайплайну

Рассмотрю создание экрана загрузки с Ford Mustang RTR-X. Исходных требований немного — авто главное в кадре, машина должна дрифтить. Так как это арт на загрузочный экран, размер надо взять с запасом, а композиция должна нормально обрезаться под все основные форматы экранов — 18:9, 16:9, 4:3.

Вызываю авто для экспорта. Для примера, машина в гараже.

image3.png

Машина готова к рендерингу после импорта в Blender и конвертации с помощью аддона.

image8.png

Прилинкую машину в файл с трассой, затем настрою камеру для динамичного ракурса. Определившись с камерой, делаю Viewport Render, чтобы проверить, как выбранный ракурс будет смотреться в игре или на промо в соцсетях.

Далее добавляю дым на сцену в качестве OpenVDB симуляции, анимирую машину вместе с камерой, поставив вместе на кривую и сдвинув на пару кадров. Это позволит получить “честный” Motion Blur на рендере, чтобы не добавлять его позже в Photoshop вручную.

image14.png

Финальный арт после небольшого композитинга и колор-коррекции.

image13.png

Плюсы подобного подхода

Собирая промки в Blender, художники могут пользоваться широким перечнем фичей, невозможных для игрового движка. Например:
  • Выбор между Realtime рендером в Eevee или точным Path Tracing в Cycles
  • Shading Nodes для создания процедурных материалов
  • Честный Motion blur (анимируя положения камеры и автомобиля)
  • OpenVDB волюметрики для эффектов тумана, дыма, огня
  • Geometry Nodes для создания point clouds (например, пыль или капли на авто)
  • Light Groups для тонкой настройки освещения после рендера
  • Render Passes для финального композитинга

Отзывы о новом пайплайне

Новый пайплайн создания промо-арта сильно облегчил нашим художникам работу и освободил время для других задач. Теперь нам не нужно тратить время на дорисовку арта, а рабочий процесс стал походить на работу фотографа — как лучше поставить свет, попробовать разные ракурсы для съемки. Время итераций сильно сократилось, потому что рендерам необходима лишь минимальная обработка — чаще всего достаточно Camera Raw фильтра, и можно уже резать арт под необходимые размеры.

Маркетинг-команде тоже лучше — для главных распродаж в году можно запросить больше картинок хорошего качества вовремя. И правки делать проще — достаточно перерендерить картинку, а в Photoshop заменить только смарт-объект. Ничего не придётся перерисовывать.


Разработка инструментов, даже относительно простых, повышает эффективность процессов и дает команде возможность больше фокусироваться на креативных задачах. Описанный в статье пайплайн успешно используется нашей арт-командой уже пару лет, и полностью отвечает ее запросам. Несмотря на частый апдейт версий Blender, он практически не требует времени на поддержку или обновление.


742 0 850 6
2
2022-06-15
Спасибо! Было полезно!
2022-06-17
"В идеале для этого нужен популярный, бесплатный 3D пакет" ...а что, много бесплатных пакетов? ))) Все работают в 3х пакетах, Максе, Мае и Блендере.. дальше идёт экзотика типа Синьки, Гудини и тд... Но из всех пакетов бесплатный только Блендер )) Поэтому задача была описана странно )
RENDER.RU