Менять одежду на персонажах из MakeHuman в Unity3d
Цель статьи, перенести персонажа из Makehuman в Unity3d, так чтобы его одежду можно было снимать и надевать прямо во время игры.
Для этого нам понадобится Makehuman, Blender3d, Unity3d и его плагин UMA (они все бесплатные). Статья написана по мотивам этого ютуб канала, повторяя за автором я набил много шишек, и теперь готов изложить своё видине.
Этап 1: Создание персонажа в Makehuman
Это самый легкий и приятный этап, тут необходимо смоделировать персонажа. Makehuman довольно простая программа поэтому не буду описывать как в ней работать.
Но есть три важных момента. Во-первых: нужно добавить скелет к модели (добавляется во вкладке Pose/Animate). В этом туториале я использую риг Game Engine. Во-вторых, если на персонаже есть одежда, то нужно отключить опцию удаления полигонов под одеждой (это можно сделать во вкладке Geometris → Clothes, и снять галочку Hide faces under clothes). В-третьих нужно экспортировать в fbx указать единицы метры. Так же, на всякий случай, можно сохранить модель.
Несколько дополнительных моментовНе надо менять позу персонажа.
Одежду можно экспортировать по частям. То-есть не надо напяливать все шмотки сразу, можно например сначала сохранить персонажа у которого только штаны с рубашкой. В блендере экспортировать их, затем вернуться в makehuman, снять старую одежду и повторить операции экспорта, например, для шляпы и ботинок.
Единицы измерения метры, значит что десять клеточек в makehuman будут означать условный метр
Этап 2: Обработка его в Blender3d
Тут нам нужно сделать три вещи:
Нормализовать модель
Добавить глобальную кость
Нарезать части тела
Запускаем Blender3d. Для начала нам нужно удалить свет, камеру и куб и импортировать нашу модель. Затем импортируем нашу модель: File → Import → fbx (и выбираем наш fbx файл)
Грабля на которую я наступилПервый раз когда потратил время на создание персонажа makehuman, в блендере нажал на экспорт вместо импорта (в результате в мой fbx файл записалась пустая сцена, и пришлось заново создавать персонажа). Тоже самое касается импорта.
Нормализация
Персонаж импортируется не в своей дефолтной позе. Если мы например с нуля смоделируем персонажа, затем зададим ему кости, то его дефолтная поза будет той, в которой мы его смоделировали. И если мы изменим ему позу при помощи костей и перейдем в режим редактирования, то сетка персонажа примет его дефолтную позу. Наша задача очистить трансформацию позы.
Очищаем трансформацию позыПереходим в блендере в режим позы
Переход в режим позыВыделяем всё, (клавиша a)
Затем нажимаем pose →clear transform → all
Очистка трансформацииЧтобы проверить что трансформации очищены, можно перейти в режим редактирования. Модель не должна при этом измениться.
После этого персонаж развернулся на 90 градусов, нужно вернуть его обратно
Вращение персонажа в блендерСначала нужно перейти в объектный режим.
Переход в объектный режимНапоминаю что мышь должна находиться на экране с моделькой. Далее нужно нажать R для перехода в режим вращения, затем X для того чтобы вращение было только по этой оси. Затем на клавиатуре набрать -90 и нажать Enter
И наконец, нужно очистить внутреннее масштабирование и вращение всех мешей.
Очистка масштабирования и вращенияЕсли мы, например, создадим два куба и первый сожмем в объектном режиме, а второй в режиме редактирования, то они сожмутся по разному. На панели трансформации в первом случае scale по всем осям будет 0.500, во втором 1.000. Это значит, что у первого куба меняется атрибут scale, а сам куб, как бы не меняется. Тоже самое с вращением.
Для модели нашего персонажа нам нужно добиться чтобы все его меши имели вращение 0° и масштабирование 1.000 (без изменения формы самих мешей естественно).
Для этого нужно, в объектном режиме выделять каждый меш (включая арматуру) нажимать на ctrl + a, и выбирать пункт rotation & scale.
Добавление глобальной кости
Теперь нам нужно добиться чтобы скелет был совместим с UMA. Для этого нужно добиться такой иерархии костей.
Global (Head= 0,0,0 Tail=0,0,0.1) // новая кость
Position (Head= 0,0,0 Tail=0,0,0.1) // бывшая Root кость
весь старый скелет (кость pelvis)
Пошаговая инструкция как этого добитьсяВыделим Root кость и переименуем её в Position. Затем выставляем у неё характеристики Transform так же как на картинке.
Далее выделяем в арматуру (у меня это Game_engine) и переходим в режим редактирования. Далее нажимаем на add → single bone
У нас появится кость с именем bone, и её нужно переименовать в Global и выставить в ней те же характеристики, что и для кости Position.
Далее нужно сделать Global кость предком кости Position. Для этого нужно сначала свернуть список дочерних костей у кости Position.
Далее выделить кость Global, затем зажав shift, выделить кость Position. Перевести мышь на экран с 3d моделью и нажать на ctrl + p, в выпадающем меню выбрать keep offset.
Нарезка персонажа
Персонаж в UMA состоит из слотов — это такие части модели на которые можно надевать/снимать какую нибудь шмотку. Например, когда мы надеваем броню на торс персонажа, у него должен исчезнуть торс и замениться торсом с доспехами.
В этом туториале мы разобъём персонажа на следующие слоты
Голова
Торс
Ноги (без ступней)
Ступни
Глаза
Волосы
Первом делом нам нужно создать сетку швов (seams mesh). Для того чтобы можно было менять те части, которые идут единой сеткой (например чтобы голова выглядела приделанной к туловищу, а не как отдельная моделька). Для этого нам нужно продублировать главную сетку.
Создание seams meshВыделяем главную сетку (в моём случае она выглядит вот так). Прочие сетки (глаза, волосы и одежду) я скрыл.
seams meshНажимаем shift + d, затем RMB
В результате она должна продублироваться.
И называем её seams mesh (либо любым другим названием).
Теперь осталось добиться того, чтобы вместо старого меша были отдельные части.
Нарезка персонажаПереходим в режим редактирования нашей главной сетки (не seams mesh).
В подрежим редактирование поверхностей.
Зажимаем alt и нажимаем на какой нибудь из прямоугольников на шее чтобы выделить полоску как на рисунке ниже (стараемся кликнуть ближе к вертикальному ребру чем к горизонтальному, иначе выделится вертикальная лента).
Далее входим в режим рентгеновского выделения
И нажимаем на c, появится кружок (если покрутить колесико мыши его размер изменится). И этим кружком выделяем голову. Внимательно смотрим чтобы не осталось не выделенных граней. У меня получилась вот такая голова.
Рентгеновское выделение можно выключить. Далее нажимаем на P и в выпадающем меню выбираем selection. Всё, голова отделена. Не забудем переименовать получившийся меш.
Теперь такую же операцию нужно проделать с другими частями. В результате у меня получилась вот такая картина. Тут поменял ракурс и выделил торс и ступни чтобы было лучше видно меши на которые я разбил модель.
Ещё я нарезал одежду и переименовал части тела.
Таким образом, мы имеем seams mesh и множество мешей если собрать которые получиться модель персонажа. Каждый с одинаковой арматурой.
Теперь экспортируем персонажа в формате fbx (желательно в ту же папку куда экспортировали из makehuman потому что там должны лежать текстуры к нему)
Этап 3: Создание UMA расы
Подготовка сцены
Открываем unity, настраиваем сцену, скачиваем вот этот ассет и импортируем его в unity. Это ничто иное как UMA — Unity Multipurpose Avatar, фреймворк который позволяет кастомизировать персонажей. Перетаскиваем префаб UMA/Getting Started/UMA_GLIB в иерархию.
Импорт персонажа
Создаём папку в юнити в которой будем работать, я назвал её characters. Перетаскиваем туда папку с нашим персонажем (fbx и текстуры). Возможно появиться сообщение о том, что некоторые текстуры не помечены как карты нормалей. Можно нажать fix now.
Для удобства при работе с UMA я закидываю всё в одну папку (в characters), потому что при создании и настройки ассетов постоянно приходиться указывать в них ссылки на друг друга. А каждый раз лазить по папкам не всегда удобно. В любом случае, после того как мы всё настроем можно будет навести порядок.
Выделяем в менеджере проекта нашу fbx модельку, в инспекторе снимаем галочку Convert Units, и нажимаем Apply. Далее переходим во вкладку rig в animation type, выбираем Humanoid и так же нажимаем Apply.
Теперь нажимаем в верхнем меню UMA → Extract T-Pose (в менеджере проекта наша fbx модель должна быть выделена). В результате должна появиться папка TPoses с экспортированной т-позой.
Создание слотов и оверлеев
В верхнем меню выбирам UMA → Slot Builder, появившийся окно я перетаскиваю рядом со вкладкой иерархии. Нажимаем на стрелочку рядом с fbx моделью и находим там часть seams mesh и перетаскиваем её в поле seams mesh в Slot Builder. В UMAMaterial выбирем UMA_defuse (для простоты). В slot destination folder переместите папку куда будут генерироваться слоты.
Теперь перетаскиваем части которые должны выглядеть единым мешем в панель automatic Drag and Drop porcessig. Это голова, торс, ноги и ступни (но не глаза и волосы). После того как закончили, в seams mesh выберите None и подобным образом перетащите глаза, волосы и одежду.
Теперь нужно создать оверлеи. Оверлей это по сути текстура, созданная специально для UMA, которую можно комбинировать с другими такими текстурами, используется например для добавления шрамов, татуировок, макияжа, рисунка на щите (ещё можно добиться чтобы цвет этого рисунка на щите менялся программно). Итак, правый клик мыши в менеджере проекта, Create → UMA → Core → Overlay Asset. В Overlay name впишите имя оверлея (например head), в material выберете тот материал который указывали при создание слотов (в нашем случае это UMA_defuse) в спойлере количество каналов укажите 1, и перетащите в появившиеся поле _MainTex соответствующую текстуру. Туже операцию проделайте для других текстур.
Создание TextRecipe и RaceData
Снова правый клик мыши в менеджере проекта Create → UMA → Core → Race Data, затем Create → UMA → Core → Text Recipe. Первый файл — это файл расы. Второй — это базовый набор слотов/оверлеев для неё. Придумайте название для них и переименуйте файлы соответствующим образом. Выделите расу, в поле Race Name введите её название, в TPose перетащите т-позу которую мы получили ранее. В Base Race Recipe перетащите рецепт который мы только что создали.
Теперь нужно назанчить Wardrobe Slots, это что-то типа ячейки инвенторя, куда можно надеть шмотку. В них помещается Wardrobe Recipe. Wardrobe Recipe по сути это сама шмотка. В чем его отличие Wardrobe Recipe от обычный слотов? Слот это сменяемая одна из частей модели, вардроп рецепт это информация о том как этот слот (шмотка) будет надеваться на тело. Например если есть шляпа, то слот шляпы будет содержать мешь шляпы, (и информацию о том, оверлеи с каким матерьялом с ним совместимы). А Wardrobe Recipe будет содержать ссылку на этот слот, нужные оверлеи, и информацию о том что нужно убрать волосы (и другую шляпу если она есть), и ещё скрыть часть головы, если её части проходят сквозь шляпу. Поэтому в Wardrobe Slots можно создать примерно вот такой список:
None
Hair
Shirt
Pants
Shoes
Теперь выделите файл с BaseRecipe, переключитесь на вкладку Slots. В поле Race Data перетащите наш файл расы (да, теперь файл расы и базовый рецепт ссылаются друг на друга). Теперь нужно перетащить слоты тела на соответствующую панель (слоты одежды и волос не обязательно перетаскивать). В результате должен получиться список из слотов. Теперь для каждого слота нужно перетащить соответствующий оверлей. В данном случае для всех частей тела используется один и тот же оверлей, и после перетаскивания он будет отображаться в панели shared overlays.
В верхнем меню нажмите UMA → Global Library, и перетащите в левую панельку папку в которой мы работали.
Добавление персонажа на сцену
Всё что мы до этого делали было подготовкой к этому шагу. Перетаскиваем префаб UMA/Getting Started/UMADynamicCharacterAvatar в сцену (можно переименовать его). В инспекторе в компоненте Dynamic Character Avatar в поле Active Race выбираем нашу расу.
Добавляем анимациюУ меня по умолчанию не запустилась анимация (для базовых рас тоже, поэтому подозреваю что это недоработка). Глубоко этот вопрос пока не изучил, но сумел добиться чтобы она воспроизводилась. Для этого под спойлером Race Animation Controllers в списке Race Animators удаляем все элементы и добавляем новый, в Race указываем нашу расу, в Animator выбираем IdleTest-w-head.
Нажимаем на Play. У вас должен появиться персонаж которого мы собрали.
Добавление одежды
Теперь создадим одежду Create → UMA → DCS → Waredrop Recipe, выделяем созданный ассет назначаем ему расу, задаём имя и назначаем Wardrobe Slot. Затем по аналогии с созданием базового рецепта, перетаскиваем на панель слот и оверлей той шмотки которую мы ходим создать. Затем перетаскиваем этот ассет в глобальную библиотеку, так же как мы делали ранее. Проделываем эту операцию для других шмоток и волос. Теперь выделяем нашего персонажа в иерархии, в спойлере Castumization → Default Recipes перетаскиваем созданные вардроп рецепты на панельку.
Если тело проходит сквозь одежду, то нужно создать сетку сокрытия. Create → UMA → Misc → Mash Hide Asset, указывам слот с частью тела, который нужно частично скрыть, нажимаем на кнопку Begin Editing и в редакторе выделяем те грани, которые будут скрываться при надевании этой шмотки. Далее в Waredrop Recipe нажимаем на кнопку Add Mesh Hide Asset, и выбираем сетку сокрытия.
Теперь можно надевать и снимать эту вещь. Для этого выбираем наш Dynamic Character Avatar, и в спойлере Customisation → Default Waredrop Recipes перетаскивам на панельку наш вардроп рецепт.
Добавление и удаление одежны программно
Для этого нужно использовать методы компонента DynamicCharacterAvatar. Для добавления SetSlot и ClearSlot для удаления, после этого нужно вызвать метод BuildCharacter. Первый аргумент SetSlot это имя слота куда необходимо надеть шмотку. Полный список доступных слотов можно посмотреть в файле рассы. Второй аргумент это имя файла нашего Waredrop Recipe. В ClearSlot нужно использовать только имя слота.
Первый аргумент в SetSlot излишен (имхо)На мой взгляд информация о том куда мы надеваем шмотку излишния. По сути значение первого аргумента SetSlot всегда совподает с полем Waredrop Slot соответвующего Waredrop Recipe.
Вот пример скрипта, вам остаеться куда нибдуь повесить методы AddWardrobe и RemoveWardrobe.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UMA;
using UMA.CharacterSystem;
public class Program : MonoBehaviour
{
// сюда нужно перетащить наш Dynamic Character Avatar
public GameObject DCA;
private DynamicCharacterAvatar avatar;
void Start(){
avatar = DCA.GetComponent();
}
public void AddWardrobe(string wardrobeSlot, string wardrobeRecipe){
avatar.SetSlot(wardrobeSlot,wardrobeRecipe);
avatar.BuildCharacter();
}
public void RemoveWardrobe(string wardrobeSlot){
avatar.ClearSlot(wardrobeSlot);
avatar.BuildCharacter();
}
}
Заключение
Спасибо что дочитали до конца, надеюсь эта статья станет для вас ещё одним шагом к созданию своей игры мечты.