Анимация в Spine, советы и рекомендации, псевдо 3D эффект
Хочу поделиться своим опытом работы со Spine — программой для создания скелетной анимации, специально заточенной под игры.
После просмотра официального гайда возникает много вопросов, поговорим про то, какие подводные камни ожидают нас при работе с этой программой на каждом этапе рабочего процесса (на примере Spine — Unity), как можно оптимизировать свою работу, а так же рассмотрим некоторые популярные фишки типа 3D эффекта. В статье будет много тяжелых гифок.
UPD: После недавнего релиза Spine версии 3.6 фишки с Json описанные в конце статьи актуальны разве что для общего развития, т.к. разработчики добавили данный функционал «из коробки».
UPD2: Layers to PNG теперь называется Photoshop to Spine, сохраняет картинки сразу в нормальном размере, а так же после появления в версии 3.8 функции trace для автоматической генерации меша по контуру текстуры и встроенной полигональной паковки атласов так заморачиваться с подготовкой картинок теперь не обязательно.
Теперь в Spine уже встроен предпросмотр готовой анимации, делается это в окне preview, там можно посмотреть как отрабатывают бленды и как одна анимация накладывается на другую. Отдельно Skeleton viewer теперь искать не обязательно. Проблем со смешиванием чаще всего удается избежать просто внимательно следя за тем какие ключи и где вы ставите.
Сразу оговорюсь, для создания программной анимации в играх есть и другие решения, Dragon Bones, Spriter, Creature, Marionette studio, плагин Puppet 2D и наверняка найдутся другие, просто я как аниматор работаю в Spine.
Схема работыКогда у нас на руках есть информация и понимание какие персонажи/анимации должны быть созданы для игры, отрисован необходимый материал — можно приступать.
Общая схема работы такова:
Первым делом необходимо подготовить рабочий материал из графических редакторов. Затем ассеты (assets, текстуры) импортируются в Spine и анимируются. На выходе мы получаем Json — файл в котором записаны все ключевые кадры трансформации костей, слотов и проч. Данный файл импортируется в движок, создается специальная skeleton data, которая добавляется на сцене в Spine game object, где наша анимация визуализируется по средствам mesh renderer, запуском можно управлять с помощью кода или же стандартным unity animator.
Непосредственно рабочий процесс в спайне выглядит следующим образом:
- Импорт текстур
- Риггинг (настройка скелета)
- Скиннинг (настройка меша и привязка его к костям)
- Анимация
- Экспорт Json и проверка
На этапе подготовки текстур нам важно понимать сколько необходимо проекций персонажа, какая часть работы будет сделана покадрово, какая программно, как грамотно разрезать персонажа и подготовить ассеты.
А также недостаточное число проекций если персонаж меняет ракурс.
Часто у персонажей есть парные элементы с идентичными изображениями — руки, ноги, глаза, и проч. В таком случае целесообразно сохранить только одну текстуру, и использовать ее два, или более, раз.
В данном случае нам будет достаточно одной проекции, и ассеты художник отрисовал хорошо. Можно приступать к импорту в спайн.
Процесс импорта текстур можно существенно ускорить используя скрипт layers to PNG, который сохраняет каждый слой из фотошопа в отдельное png изображение, при этом записывает Json файл в котором содержится информация о расположении текстур, импортируя его в спайн мы получаем готового собранного персонажа.
1) Экспортируем из фотошопа с помощью скрипта Json и PNG картинки (можно указать скеил фактор) 2) Импортируем json в спайн file-import data 3) Указываем путь к текстурам подробнее
Однако у такого способа есть ряд недостатков — скрипт сохраняет изображения без сжатия, что непрактично. Просто пересохранив слои через file-generate-image assets мы уменьшим вес изображения приблизительно в 10 раз.
Далее, необходимо не забывать разворачивать ваши в спрайты в горизонтальное или вертикальное положение, и стирать все лишнее, т.к. скрипт сохранит изображения прямо в том положении в котором они находятся в фотошопе.
Если для проекта необходима покадровая анимация (напр. огонь, спецэффекты, и проч.) — материалы необходимо отрисовать заранее. Далее с помощью adobe after effects и скрипта ae_to_spine мы можем в пару кликов перенести последовательность кадров в Spine.
Аналогично скрипту layers to png. Подробнее
Рекомендую заранее продумать концепцию наименования, материалы часто приходят в формате «слой 1 (копия) 5», это не слишком практично, для каждой текстуры в проекте необходимо сделать уникальное название, что бы не вызвать проблемы при запаковке атласов. Вполне пригоден вариант формата CharacterVyasya_Skin_a_Hand_R_1.
Тут во многом нам может помочь инструмент find and replace который позволяет быстро переименовывать, указывать путь для большого количества объектов.
РиггингНастраивая скелет для персонажа нужно уже думать о том, что, скорее всего, в процессе работы над игрой анимацию нужно будет корректировать, подправлять, поэтому желательно сделать его максимально гибким, что бы процесс правок был максимально простым и быстрым.
Тут может помочь введение дополнительных костей-контролов для разбиения движения по осям X и Y (т.к. в спайне остутствует функция separate dimentions).
Сложное движение ящера суммируется из нескольких составляющих: вертикального, горизонтального и для возможности быстрой корректировки добавлен глобальный контрол.
Тут же маленький типс, если вдруг чувствуется нагромождение из за излишнего количества костей — попробуйте покрутить настройку bone scale:
Смотрите примеры готовых ригов из образцов поставляемых вместе со спайном, или в сети.
Так же полезные материалы можно искать на behanсe, форуме, соответствующих сообществах в социальных сетях.
СкиннингМеш — Один из ключевых инструментов в спайне, накладывая на его текстуру мы получаем возможность ее деформировать, искажать, создавать иллюзию 3D.
При создании меша помните: чем меньше вертексов — тем проще контролировать анимацию.
Т.к. деформация меша потребляет ресурсы CPU, при создании сетки стоит руководствоваться принципом необходимого минимума, наглядно это можно рассмотреть на примере рига кончика хвоста динозавра:
Не забывайте про возможность дублирования целой иерархии меша вместе с костями и весами. Это поможет значительно сэкономить время при риге повторяющихся объектов.
ПроизводительностьВ конечном итоге у нас возникает вопрос — а сколько вертексов можно использовать? Разработчики спайна конкретно не отвечают на этот вопрос, и отсылают к вкладке Spine Metrics, где мы можем отследить суммарное количество элементов в сцене, но при этом говорят о необходимости проведения кастомных тестов производительности.
Важно помнить что трансформация меша, таймлайны, констрейны грузят CPU, а статичная геометрия — GPU. В общем, я бы советовал в случае работы над ключевыми персонажами не сильно заморачиваться по поводу точек, плюс минус десяток не сыграет никакой роли, однако в случае объекта из окружения, который будет повторяться сотню раз, каждый сэкономленный вертекс пойдет на пользу.
И так, когда наш персонаж настроен можно переходить к анимации:
АнимацияСама по себе анимация это очень большая тема и явно не для обсуждения в рамках одной статьи. Тут я ограничусь банальными советами в ключе:
- Не забывайте про художественную часть, старайтесь сделать анимацию максимально выразительной
- Следуйте диснеевским принципам анимации
- Импортируйте материал в локацию, часто только после этого становятся видны косяки.
Это то за что так любят спайн — возможность деформировать изображение с помощью меша тем самым создавая трехмерный эффект.
Для себя я отметил несколько способов создания псевдо 3Д:
- Анимация непосредственно вертексов в меше
- Много костей в ключевых точках меша, анимируются кости
- Кости ставятся выборочно, а далее тщательно настраиваются веса в меше
- Комбинированный способ, все сведено под глобальные контролы
Проставляются кости в ключевых точках меша:
Анимируя кости создаем трехмерный эффект:
Можно сделать анимацией вертексов в меше, но как мы видим по сравнению с кубом точек значительно больше:
Аналогично кубу, кости в ключевых точках меша. По затраченному времени этот способ не лучше предыдущего:
Было бы гораздо более гибко свести риг под один глобальный контрол с помощью констрейнов, двигая одним управлять всеми костями:
То же самое, можно сделать без лишней массы костей,
Для этого каждому вертексу тщательно подбирается значение в весах. Такой способ можно считать оптимальным для округлых поверхностей.
Из примеров видно что анимация непосредственно точек в меше это один из самых негибких вариантов, который в случае необходимости будет трудозатратно переделывать. К этому стоит добавить что в некоторых других рантаймах, помимо юнити, эта фича не поддерживается. Поэтому рекомендую по возможности не трогать меш и управлять им с помощью костей.
По аналогии можно сделать деформацию любой геометрической формы, тем самым добавив вашей анимации выразительности.
И так, мы просидели несколько часов над ключевыми кадрами, мешами, и сделали анимацию персонажа:
ТестированиеДалее можно отправлять нашу анимацию в движок. Однако часто возникают ситуации когда внешний вид анимации в спайне и в рантайме существенно отличается, а т.к. каждое взаимодействие аниматор-программист занимает определенное время, лучше заранее провести тест анимации в рантайме, в ходе которого выявятся основные косяки, и только потом отдать работу будучи уверенным что все хорошо.
Если ваш аниматор не дружит с движком, можно использовать Skeleton Viewer
Какие проблемы возникают наиболее часто:
- Вы забыли положить некоторые ассеты, или наоборот в экспорт попало лишнего (рабочие файлы, референсы, и проч) — тут все очевидно — перед тем как отдать материал тщательно проверяйте что должно быть в проекте а что нет
- несовпадение на стыках анимации — можно попробовать выставить в юнити длительность перехода, тем самым сгладив стык. Или поправить ключи если такое возможно
- текстуры отображаются некорректно
- после отработки анимация выглядит не так как раньше
Чаще всего такое происходит из за неправильной композиции текстуры — меш должен четко соответствовать размеру спрайта.
После отработки анимация выглядит не так как раньшеИзначально овираптор сидит на гнезде с яйцами, потом встает и отходит в сторону. Казалось бы, когда анимация начнется с начала, он должен таким же образом сидеть на гнезде, однако т.к. мы сдвинули его в предыдущей анимации он будет смещен до тех пор пока не будет поставлен ключом в соответствующую позицию.
Происходит это потому что в рантайме анимация просчитывается не из дефолтного положения, а как бы из текущего. Т.е. если мы один раз включим текстуру и не выключим — она останется в таком положении во всех анимациях. Тоже самое и с другими ключами. Это скорее не баг, а фича, но к сожалению аниматор не видит реальной картины пока не импортирует свой материал в рантайм. Решить данный вопрос можно несколькими способами:
1) Проставить ключи на всех свойствах всех объектов в начале и в конце каждой анимации. На первый взгляд слегка муторно, но таким образом вы полностью обезопасите себя от нежданных сюрпризов. Использование фильтров и горячих клавиш ускорит процесс.
Красным выделена иконка фильтра объектов по костям и кнопка для быстрого разворачивания иерархии:
Горячие клавиши по умолчанию:
2) Использовать скрипт setToSetupPose, который как бы и заставляет проигрываться анимацию из дефолтного состояния. Но такой метод имеет существенный недостаток — Setup Pose выставляется мгновенно, а рендер меняет картинку на соответствующую только со следующего кадра. Таким образом мы имеем проскакивание лишнего кадра между анимациями, выглядит это неприятно. Соответствующее issue уже стоит на доске у разработчиков.
Мы можем экспортировать из спайна Json, провести с ним какие-либо манипуляции, и импортировать обратно, получив определенный результат. Это очень мощный инструмент т.к. мы получаем доступ ко всем компонентам проекта, в свою очередь нам это может очень помочь в определенных ситуациях:
- При необходимости смержить несколько проектов
- При необходимости скопировать иерархию костей вместе с анимацией
- При необходимости откатиться на более старую версию
- Любое другое применение, которое придет вам на ум
Часто возникает необходимость держать анимации в одной сцене, например как тут:
Сам жук в игре появляется в множестве других сцен и был скопирован из одной из них. Однако теперь в проекте два скелета, и соответственно на выходе будет 2 json и 2 объекта на сцене, что добавит необходимость делать определенную логику синхронного запуска этих анимаций для их совмещения во времени, а так же нужно будет точно совместить объекты по положению в локации. Можно упростить себе жизнь отдав материал в одной сцене. Для этого два json нужно смержить.
Для этого есть как минимум два способа: руками и скриптом.
РукамиКопируем куски кода из одного json в другой, в соответствующие категории: слоты к слотам, кости к костям, анимации к анимациям, и т.д. Что бы не возникло конфликтов, важно соблюсти корректность наименования объектов, что бы названия из одного json не совпадали с названиями из другого. Проще всего этого добиться заранее в спайне присвоив всем объектам в именах свой уникальный индекс типа _skel1_ и _skel2_. Этот способ слегка затратный по времени, но меня еще не подводил.
Предельно простой пример для демонстрации принципа, два скелета с костями в одном проекте:
В результате имеем все в одном проекте:
Проблемы могут возникнуть в проектах с скинами, по возможности старайтесь не менять иерархию костей.
Более сложный пример с лягушкой: (Осторожно, длинные файлы)
Skeleton Merger ToolДобрые люди написали специальную тулзу для мержинга. Ознакомиться и скачать можно по ссылке . Использовать ее достаточно удобно, включен автоматический ренейминг объектов, однако я не раз сталкивался с ошибками.
Дублирование объектов вместе с анимациейВ спайне отсутствует вложенность композиций (аналог прекомпоз в After Effects или символ во Flash), однако, как показывалось выше, есть возможность продублировать объекты, с сохранением всех зависимостей, но ключи анимации в таком случае не копируются. Не сложно догадаться что, для того что бы не делать анимацию заново, можно переназначить ее на дубликат костей, для этого надо всего лишь перебить в Json имена. Опять же, это проще сделать если у каждой кости будет свой уникальный индекс.
Есть муравей с анимацией. Задача сделать в спайне целую цепочку бегающих друг за другом муравьев. При дублировании муравья анимация не копируется. Обратите внимание, у первого муравья в названии стоит индекс _skel_1_, у второго _skel_2_.
Экспортируем Json и открываем его текстовым редактором. Код анимации walk_1 копируем, находим там все участки _skel_1_:
заменяем их на _skel_2_
Вставляем обратно. Таким образом мы переназначили анимацию на другие кости. Сохраняем json, и импортируем его в спайн путем file — import data. Теперь у нас два бегающих муравья.
Откатиться до старой версииПроекты сохраненные в более новой версии будут не совместимы со старыми. Иногда это может стать проблемой, и для ее решения есть несколько способов:
Руками перебить версию в jsonПоможет если между версиями небольшой промежуток, и нет принципиальных различий в алгоритмах работы анимации.