Анімація в Spine, поради і рекомендації, псевдо 3D ефект

Хочу поділитися своїм досвідом роботи з Spine — програмою для створення скелетної анімації, спеціально заточеною під ігри.

Після перегляду офіційного гайда виникає багато питань, поговоримо про те, які підводні камені чекають нас при роботі з цією програмою на кожному етапі робочого процесу (на прикладі Spine — Unity), як можна оптимізувати свою роботу, а так само розглянемо деякі популярні фішки типу 3D ефекту. У статті буде багато важких гифок.

Відразу обмовлюся, для створення програмної анімації в іграх є й інші рішення, Dragon Bones, Spriter, Creature, Marionette studio, плагін Puppet 2D і напевно знайдуться інші, просто я як аніматор працюю в Spine.

Наочна демонстрація принципу скелетної анімації

Схема роботи
Коли у нас на руках є інформація і розуміння які персонажі/анімації повинні бути створені для гри, отрисован необхідний матеріал — можна приступати.

Загальна схема роботи така:

Насамперед необхідно підготувати робочий матеріал з графічних редакторів. Потім ассеты (assets, текстури) імпортуються в Spine і анімуються. На виході ми отримуємо Json — файл в якому записані всі ключові кадри трансформації кісток, слотів і ін. Даний файл імпортується в движок, створюється спеціальна skeleton data, яка додається на сцені в Spine game object, де наша анімація візуалізується за коштами mesh renderer, запуском можна керувати за допомогою коду або ж стандартним unity animator.

Безпосередньо робочий процес в спайне виглядає наступним чином:

  1. Імпорт текстур
  2. Риггинг (параметри скелета)
  3. Скиннинг (настройка меша і прив'язка його до кісток)
  4. Анімація
  5. Експорт Json і перевірка
В якості прикладу спробуємо зробити анімацію ось такого персонажа:

Імпорт текстур
На етапі підготовки текстур нам важливо розуміти скільки необхідно проекцій персонажа, яка частина роботи буде зроблена покадрово, яка програмно, як грамотно розрізати персонажа і підготувати ассеты.

Типові помилки:

не малювати текстури рухомих частин де їх не видно:

неправильно поставлені тіні

А також недостатнє число проекцій якщо персонаж змінює ракурс.

Часто у персонажів є парні елементи з ідентичними зображеннями — руки, ноги, очі, та ін. У такому разі доцільно зберегти лише одну текстуру, і використовувати її два або більше разів.

В даному випадку нам буде достатньо однієї проекції, і ассеты художник відмалювати добре. Можна приступати до імпорту в спайн.

Процес імпорту текстур можна істотно прискорити використовуючи скрипт layers to PNG, який зберігає кожен шар з фотошопу в окреме png зображення, при цьому записує Json файл в якому міститься інформація про розташування текстур, імпортуючи його в спайн ми отримуємо готового зібраного персонажа.

Як користуватися скриптом layers to PNG1) Експортуємо з фотошопа з допомогою скрипта Json і PNG картинки (можна вказати скеил фактор)
2) Імпортуємо json в спайн file-import data
3) Вказуємо шлях до текстур
докладніше


Однак у такого способу є ряд недоліків — скрипт зберігає зображення без стиснення, що непрактично. Просто пересохранив шари через file-generate-image assets ми зменшимо вага зображення приблизно в 10 разів.

Далі, необхідно не забувати розгортати ваші в спрайт в горизонтальне або вертикальне положення, і прати все зайве, т. к. скрипт збереже зображення прямо в тому положенні, в якому вони знаходяться в фотошопі.



Якщо для проекту необхідна покадрова анімація (напр. вогонь, спецефекти, та ін.) — матеріали необхідно промалювати заздалегідь. Далі за допомогою adobe after effects і скрипта ae_to_spine ми можемо в пару кліків перенести послідовність кадрів в Spine.

Як користуватися скриптом AE to SpineАналогічно скрипту layers to png. Докладніше


Рекомендую заздалегідь продумати концепцію найменування, матеріали часто приходять у форматі «шар 1 (копія) 5», це не дуже практично, для кожної текстури в проекті необхідно зробити унікальну назву, що б не викликати проблеми при запаковке атласів. Цілком придатний варіант формату CharacterVyasya_Skin_a_Hand_R_1.

Тут багато в чому нам може допомогти інструмент find and replace, який дозволяє швидко перейменовувати, вказувати шлях для великої кількості об'єктів.

інструмент find and replace

Риггинг
Налаштовуючи скелет для персонажа треба вже думати про те, що, швидше за все, в процесі роботи над грою анімацію потрібно буде коригувати, підправляти, тому бажано зробити його максимально гнучким, що б процес правок був максимально простим і швидким.

Тут може допомогти введення додаткових кісток-контролів для розбиття руху по осях X і Y (т. к. в спайне остутствует функція separate dimentions).

Приклад рига з додатковими контроламиСкладний рух ящера підсумовується з декількох складових: вертикального, горизонтального і для можливості швидкої коригування додано глобальний контроль.



Тут же маленький типс, якщо раптом відчувається нагромадження через зайвої кількості кісток — спробуйте покрутити налаштування bone scale:



Дивіться приклади готових ригов із зразків поставляються разом з спайном, або в мережі.

Невеличка добірка досить відомих авторів, у яких є що подивитися:зауважив sоren Nielsen
Hwadock Jang
Charles Duchesne
Dao Le Trong
Spine progress
Walk test

Так само корисні матеріали можна знайти на behanсe, форуме, відповідних спільнотах в соціальних мережах.

Скиннинг
Меш — Один з ключових інструментів у спайне, накладаючи на його текстуру ми отримуємо можливість її деформувати, спотворювати, створювати ілюзію 3D.

При створенні меша пам'ятайте: чим менше вертексов — тим простіше контролювати анімацію.

Демонстрація

Т. к. деформація меша споживає ресурси CPU, при створенні сітки варто керуватися принципом необхідного мінімуму, наочно це можна розглянути на прикладі рига кінчика хвоста динозавра:

1 варіант — недостатньо точок, видно злами на картинці:

2, 3 варіант — добре:


4 варіант — зайва кількість точок, які не виконують ніякої функції, нікуди не годиться:

Не забувайте про можливість дублювання цілої ієрархії меша разом з кістками і вагами. Це допоможе значно заощадити час при ризі повторюваних об'єктів.

Лайфхак як продублювати цілу ієрархію
Продуктивність
В кінцевому підсумку у нас виникає питання — а скільки вертексов можна використовувати?
Розробники спайна конкретно не відповідають на це питання, і відсилають до вкладці Spine Metrics, де ми можемо відстежити сумарна кількість елементів у сцені, але при цьому говорять про необхідність проведення кастомних тестів продуктивності.

Важливо пам'ятати що трансформація меша, таймлайны, констрейны вантажать CPU, а статична геометрія — GPU. Загалом, я б радив у разі роботи над ключовими персонажами не сильно заморочуватися з приводу точок, плюс-мінус десяток не зіграє ніякої ролі, однак у випадку об'єкта з оточення, який буде повторюватися сотню разів, кожен зекономлений вертекс піде на користь.

І так, коли наш персонаж налаштований можна переходити до анімації:



Анімація
Сама по собі анімація це дуже велика тема і явно не для обговорення в рамках однієї статті.
Тут я обмежуся банальними радами ключі:

  • Не забувайте про художню частину, намагайтеся зробити анімацію максимально виразною
  • Дотримуйтесь диснеївським принципів анімації
  • Імпортуйте матеріал в локацію, часто тільки після цього стають видні косяки.
3D-ефект
Це те за що так люблять спайн — можливість деформувати зображення з допомогою меша, тим самим створюючи тривимірний ефект.

Демонстрація

Для себе я відзначив кілька способів створення псевдо 3Д:

  1. Анімація безпосередньо вертексов в меші
  2. Багато кісток в ключових точках меша, анімуються кістки
  3. Кістки ставляться вибірково, а далі ретельно налаштовуються ваги в меші
  4. Комбінований спосіб, все зведено під глобальні контроли
Наочно принцип побудови тривимірного ефекту можна розглянути на геометричних примітивах:

КубПроставляються кістки в ключових точках меша:


Анимируя кістки створюємо тривимірний ефект:




Трохи складніший приклад зі сферою:

Можна зробити анімацією вертексов в меші, але як ми бачимо порівняно з кубом точок значно більше:



Аналогічно кубу, кістки в ключових точках меша. По витраченому часу цей спосіб не краще попереднього:



Було б набагато більш гнучко звести клунь під один глобальний контрол з допомогою констрейнов, рухаючи одним керувати усіма кістками:



Те ж саме можна зробити без зайвої маси кісток,



Для цього кожному вертексу ретельно підбирається значення в терезах. Такий спосіб можна вважати оптимальним для округлих поверхонь.



З прикладів видно що анімація безпосередньо точок в меші це один з найбільш негнучких варіантів, який у разі необхідності буде трудомістке переробляти. До цього варто додати, що в деяких інших рантаймах, крім юнити, ця фіча не підтримується. Тому рекомендую по можливості не чіпати меш і управляти їм за допомогою кісток.

За аналогією можна зробити деформацію будь-якої геометричної форми, тим самим додавши вашої анімації виразності.

І так, ми просиділи кілька годин над ключовими кадрами, мешами, і зробили анімацію персонажа:

Що вийшло

Тестування
Далі можна відправляти нашу анімацію в движок. Проте часто виникають ситуації коли зовнішній вид анімації в спайне і в рантайме істотно відрізняється, а тому що кожна взаємодія аніматор-програміст займає певний час, краще заздалегідь провести тест анімації в рантайме, в ході якого виявляться основні косяки, і тільки потім віддати будучи впевненим, що все добре.

Якщо ваш аніматор не дружить з движком, Skeleton Viewer

Які проблеми виникають найбільш часто:

  1. Ви забули покласти деякі ассеты, або навпаки експорт потрапило зайвого (робочі файли, референси, та ін) — тут все очевидно — перед тим як віддати матеріал ретельно перевіряйте що повинно бути в проекті а що ні
  2. розбіжність на стиках анімації — можна спробувати виставити в юніті тривалість переходу, тим самим вирівнявши стик. Або поправити ключі якщо таке можливо
  3. текстури відображаються некоректно
  4. після відпрацювання анімація виглядає не так, як раніше

Некоректне відображення текстур

Найчастіше таке відбувається через неправильну композиції текстури — меш повинен чітко відповідати розміру спрайту.



Інакше буде ось так.

Після відпрацювання анімація виглядає не так, як раніше

ПрикладСпочатку овираптор сидить на гнізді з яйцями, потім встає і відходить убік. Здавалося б, коли анімація почнеться з початку, він повинен таким же чином сидіти на гнізді, однак оскільки ми зрушили його в попередній анімації він буде зміщений до тих пір, поки не буде поставлений ключем у відповідну позицію.



Відбувається це тому, що в рантайме анімація прораховується не з дефолтного положення, а як би з поточного. Тобто якщо ми один раз включимо текстуру і не вимкнемо — вона залишиться в такому положенні у всіх анімація. Теж саме і з іншими ключами. Це скоріше не баг, а фіча, але на жаль аніматор не бачить реальної картини поки не імпортує свій матеріал в рантайм. Вирішити дане питання можна декількома способами:

1) Проставити ключі на всі властивості всіх об'єктів на початку і в кінці кожної анімації. На перший погляд трохи клопітно, але таким чином ви убезпечите себе від несподіваних сюрпризів. Використання фільтрів і гарячих клавіш прискорить процес.

Червоним виділена іконка фільтра об'єктів по кістках і кнопка для швидкого розгортання ієрархії:



Гарячі клавіші за замовчуванням:

Key Active: L
Selected Key: ctrl + L
Key Dopesheet: ctrl + shift + L
Key Translation, Key Rotation, Key Scale, Key Shear, Key Color — потрібно налаштовувати самому
2) Використовувати скрипт setToSetupPose, який як би і змушує програватися анімацію з дефолтного стану. Але такий метод має істотний недолік — Setup Pose виставляється миттєво, а рендер змінює картинку на відповідну лише з наступного кадру. Таким чином ми маємо проскакивание зайвого кадру між анімаціями, виглядає це неприємно. Відповідне issue вже стоїть на дошці у розробників.

Setup Pose баг

JSON
Ми можемо експортувати з спайна Json, провести з ним якісь маніпуляції, і імпортувати назад, отримавши певний результат. Це дуже потужний інструмент оскільки ми отримуємо доступ до всіх компонентів проекту, в свою чергу нам це може дуже допомогти в певних ситуаціях:

  1. При необхідності смержить кілька проектів
  2. При необхідності скопіювати ієрархію кісток разом з анімацією
  3. При необхідності відкотитися на більш стару версію
  4. Будь-яке інше застосування, яке прийде вам на розум

Мержинг проектів

Часто виникає необхідність тримати анімації в одній сцені, наприклад як тут:

Жаба їсть жукаСам жук в грі з'являється в безлічі інших сцен і був скопійований з однією з них. Однак тепер в проекті два скелети, і відповідно на виході буде 2 json та 2 об'єкта на сцені, що додасть необхідність робити певну логіку синхронного запуску цих анімацій для їх поєднання в часі, а так само потрібно буде точно поєднати об'єкти по положенню в локації. Можна спростити собі життя віддавши матеріал в одній сцені. Для цього два json потрібно смержить.



Для цього є як мінімум два способи: руками і скриптом.

Руками
Копіюємо шматки коду з одного json в інший, у відповідні категорії: слоти до слотів, кістки до кісток, анімації до анимациям, і т. д. Що б не виникло конфліктів, важливо дотримати коректність найменування об'єктів, що б назви з одного json не збігалися з назвами з іншого. Найпростіше цього досягти заздалегідь в спайне присвоївши всіх об'єктах в іменах свій унікальний індекс типу _skel1_ і _skel2_. Цей спосіб злегка витратний за часом, але мене ще не підводив.

ПрикладиГранично простий приклад для демонстрації принципу, два з кістками скелета в одному проекті:



Скелет 1
{
"skeleton": { "hash": "ZMTMZiuTD2M2gnBhJR0JLPQWOws", "spine": "3.4.02", "width": 0, "height": 0, "images": "" },
"онлайн": [
{ "name": "root_skel1_" },
{ "name": "bone1_skel1_", "parent": "root_skel1_", "length": 26.95, "rotation": 360, "x": 11.09, "y": -9.65, "color": "00ff00ff" },
{ "name": "bone2_skel1_", "parent": "bone1_skel1_", "length": 26.95, "x": 26.27, "color": "00ff00ff" },
{ "name": "bone3_skel1_", "parent": "bone2_skel1_", "length": 26.95, "x": 26.57, "color": "00ff00ff" },
{ "name": "bone4_skel1_", "parent": "bone3_skel1_", "length": 26.95, "x": 25.97, "color": "00ff00ff" }
],
"animations": {
"animation": {}
}
}


Скелет 2
{
"skeleton": { "hash": "osF6oBu7PH6sMNfjN7pm2EwQ8fY", "spine": "3.4.02", "width": 0, "height": 0, "images": "" },
"онлайн": [
{ "name": "root_skel2_" },
{ "name": "bone1_skel2_", "parent": "root_skel2_", "x": 19.25, "y": 26.63, "color": "fff100ff" },
{ "name": "bone2_skel2_", "parent": "bone1_skel2_", "x": 27.14, "color": "fff100ff" },
{ "name": "bone3_skel2_", "parent": "bone2_skel2_", "x": 25.57, "color": "fff100ff" },
{ "name": "bone4_skel2_", "parent": "bone3_skel2_", "x": 27.14, "color": "fff100ff" }
],
"animations": {
"animation": {}
}
}


Сполучені скелети
{
"skeleton": { "hash": "ZMTMZiuTD2M2gnBhJR0JLPQWOws", "spine": "3.4.02", "width": 0, "height": 0, "images": "" },
"онлайн": [
{ "name": "root" },
{ "name": "root_skel1_", "parent": "root" },
{ "name": "bone1_skel1_", "parent": "root_skel1_", "length": 26.95, "rotation": 360, "x": 11.09, "y": -9.65, "color": "00ff00ff" },
{ "name": "bone2_skel1_", "parent": "bone1_skel1_", "length": 26.95, "x": 26.27, "color": "00ff00ff" },
{ "name": "bone3_skel1_", "parent": "bone2_skel1_", "length": 26.95, "x": 26.57, "color": "00ff00ff" },
{ "name": "bone4_skel1_", "parent": "bone3_skel1_", "length": 26.95, "x": 25.97, "color": "00ff00ff" },
{ "name": "root_skel2_", "parent": "root" },
{ "name": "bone1_skel2_", "parent": "root_skel2_", "x": 19.25, "y": 26.63, "color": "fff100ff" },
{ "name": "bone2_skel2_", "parent": "bone1_skel2_", "x": 27.14, "color": "fff100ff" },
{ "name": "bone3_skel2_", "parent": "bone2_skel2_", "x": 25.57, "color": "fff100ff" },
{ "name": "bone4_skel2_", "parent": "bone3_skel2_", "x": 27.14, "color": "fff100ff" }
],
"animations": {
"animation": {}
}
}


В результаті маємо все в одному проекті:



Проблеми можуть виникнути у проектах з скінами, по можливості намагайтеся не змінювати ієрархію кісток.

Більш складний приклад з жабою:
(Обережно, довгі файли)

Жук
Лягушка
Жук+Жаба


Skeleton Merger Tool
Добрі люди написали спеціальну тулзу для мержинга. Ознайомитися та скачати можна за посиланням . Використовувати її досить зручно, включений автоматичний ренеймінг об'єктів, однак я не раз стикався з помилками.

Дублювання об'єктів разом з анімацією

У спайне відсутня вкладеність композицій (аналог прекомпоз в After Effects або символ у Flash), однак, як показувалося вище, є можливість продублювати об'єкти, з збереженням всіх залежностей, але ключі анімації в такому випадку не копіюються. Не складно здогадатися що, для того що б не робити анімацію заново, можна перепризначити її на дублікат кісток, для цього треба всього лише перебити в Json імена. Знову ж таки, це простіше зробити, якщо у кожної кістки буде свій унікальний індекс.

ПрикладЄ мураха з анімацією. Завдання зробити в спайне ланцюжок бігають один за одним мурах. При дублюванні мурашки анімація не копіюється. Зверніть увагу, у першого мурашки в назві варто індекс _skel_1_, у другого _skel_2_.



Експортуємо Json і відкриваємо його текстовим редактором. Код анімації walk_1 копіюємо, знаходимо там всі ділянки _skel_1_:

"animations": {
"walk_1": {
"онлайн": {
"US_2_skel_1_": {
"rotate": [
{
"time": 0,
"angle": -42.21,
"curve": [ 0.25, 0, 0.75, 1 ]
},
{
"time": 0.4,
"angle": -0.92,
"curve": [ 0.25, 0, 0.75, 1 ]
},
{ "time": 0.8, "angle": -42.21 }
]
},
....

замінюємо їх на _skel_2_

....
"US_2_skel_2_": {
"rotate": [
{
"time": 0,
"angle": -42.21,
"curve": [ 0.25, 0, 0.75, 1 ]
},
{
"time": 0.4,
"angle": -0.92,
"curve": [ 0.25, 0, 0.75, 1 ]
},
{ "time": 0.8, "angle": -42.21 }
},
...

Вставляємо назад. Таким чином ми перепризначили анімацію на інші кістки. Зберігаємо json, і імпортуємо його в спайн шляхом file — import data. Тепер у нас два бігають мурашки.



Відкотитися до старої версії

Проекти збережені в більш нової версії будуть не сумісні зі старими. Іноді це може стати проблемою, і для її рішення є кілька способів:

Руками перебити версію в json
"skeleton": { "hash": "", "spine": "3.4.02", "width": 0, "height": 0, "images": "" },

Допоможе якщо між версіями невеликий проміжок, і немає принципових відмінностей в алгоритмах роботи анімації.

JsonRollback tool
Ознайомитися з принципом роботи і скачати можна за адресою.

Резюме
  • Чітко позначайте які завдання у чому ви робите
  • Використовуйте скрипти для прискорення роботи
  • Робіть гнучкий клунь і не переборщуйте з мешем
  • Перед відправкою тестуйте матеріал в рантайме
  • Не соромтеся залізти в json якщо це заощадить вам час
Спасибі за увагу, напевно якщо ви дочитали статтю до цього моменту у вас виникли питання або зауваження, з задоволенням прочитаю все в коментарях.

p.s. Стаття писалася аніматором здебільшого для аніматорів, якщо ви програміст і у вас «рукалицо», можете висловитися в коментарях.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.