Разработка ремейка методами чайника. Часть 5

Когда я написал прошлую статью, то думал что наконец-таки закончил с мучениями в блендере и могу заняться привычным мне кодингом. Но блендер так не думал… Под ночные новогодние кутежи из клуба напротив, я только и занимался тем, что пытался подобрать идеальный набор параметров ткани для парусов всех возможных кораблей.

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

Страдания с коллизией в блендере

Как можно было видеть по прошлой презентации процедурного генерирования парусов, им катастрофически не хватало коллизии с мачтой. Вопрос решается крайне просто - накинуть коллизию на мачту, и все счастливы! Да ведь…?

Из-за того, что паруса в состоянии покоя пересекают мачты, если им сходу накидывать коллизию, то ткань начинает путаться, растягиваться, заворачиваться под такими углами, что фпс блендера опускается ниже 1! Но у нас есть позиция из которой можно начать применять коллизию - как раз после того как паруса завершили адаптироваться к симуляции ветра. Так что логика получилась довольно простая:

  • Включить симуляцию ветра
  • Подождать пока паруса не стабилизируются
  • Выключить симуляцию ветра
  • Включить коллизию у мачт и корпуса
  • Записать результат как Shape Keys

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

Страдания с импортом сокетов

Изначально плагин сбора корабля размещал локаторы и модели раздельно. При чем внутри локатора могла размещаться модель, которую мы подгружаем из отдельного файла(mast1 например). Но UE нужно четкое распределение сокета и модели за которой он размещен. Поэтому пришлось переписывать иерархию, до и после:

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

rey_b201 явно не относится к корпусу посудины
rey_b201 явно не относится к корпусу посудины

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

Наименования у мешей я тоже постарался немного стандартизировать
Наименования у мешей я тоже постарался немного стандартизировать

Казалось бы победа, наконец-то можно работать! Но… к нам снова постучался UE. Дело в том, что паруса экспортируются как Armature, которая в свою очередь - конвертируется в Skeletal Mesh. И вот ведь неприятность - в этот меш нельзя добавлять сокеты как в примере выше. Разумеется я пошел копать интернеты, и вышел на плагин интеграции UE с блендером, в котором есть специальная кнопка копирования сокетов по одной модели. Неприятно конечно, но лучше чем руками все сокеты прописывать. Однако и тут меня ждало разочарование, потому что плагину обязательно нужно, чтобы сокет был закреплен за костью, а у меня сокеты могут размещаться в статичных позициях паруса без всяких костей. Выбирая между тем, чтобы создавать лишние кости, и просто написать свою реализацию копирования, я выбрал второе. Благо в данном случае реализация крайне проста!

К слову, в имя кости мне пришлось добавлять название модели, иначе при массовом импорте парусов из одного FBX, UE жалуется на повторение имени и добавляет к нему цифры. Может быть кто-то знает как это пофиксить?
К слову, в имя кости мне пришлось добавлять название модели, иначе при массовом импорте парусов из одного FBX, UE жалуется на повторение имени и добавляет к нему цифры. Может быть кто-то знает как это пофиксить?

Баги от UE и новое море

И вот настал момент, когда все необходимые модели импортированы и можно приступить к коду. Немного подправив генерацию тросов, я принялся их тестировать на корабле на ходу. И стала очевидна проблема с исчезновением тросов… т.е. они никуда не удаляются, но текстура становится полностью прозрачной если модель перемещается в пространстве. При чем проблема есть и при простой прокрутке камеры, её можно заметить в видео-презентации из третьей части, но это было не настолько критично.

Я вышел в интернет с таким вопросом. Как оказалось, баг возник начиная с версии 5.0 и поправили его буквально недавно в 5.1. Я не буду описывать все “прелести” с которыми я столкнулся в процессе обновления, но да, баг поправился, хотя странное размытие осталось! А еще, море стало еще красивее!

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

Архитектура

Немного расскажу об архитектуре Blueprint-а кораблей. Все корабли наследуются от BP_Ship, в котором реализована логика генерации тросов, расчет скорости перемещения, управление и прочее. В наследнике размещаются куски корабля, а так-же мачты как отдельные акторы.

Мачты так-же наследуются от абстракции, из логики: имитации точки pivot, для поворота реи в нужной позиции, установка морфов для парусов согласно направления ветра и позиции в анимации, отлов событий от корабля на действия с парусами и собственно их исполнение. А еще создание Dynamic Instance Material, к нему мы еще вернемся.

Таким образом, получилось разделить ответственность между судном и его мачтами. Для расчета скорости достаточно посчитать состояние каждого паруса от 0 до 1, сложить и разделить на их кол-во. Затем точно так-же посчитать состояние для всех мачт вцелом. В будущем к этому отлично впишется модификатор полученных повреждений.

Morph Targets и внешние факторы

Как вы, я надеюсь, помните, для имитации влияния ветра на парус я сгенерировал у парусов отдельный морф WindStrength. Выкручиваешь его в 1, и парус красиво надувается в одну сторону. -1 в другую. Собственно с учетом этой логики, я и написал логику подстраивания паруса под направление ветра. Но в процессе тестирования заметил как парус при отклонении в отрицательное положение, неестественно искривлялся и увеличивался в размерах.

Стало очевидно, что моя идея с отрицательными морфами - очень плохая, и нужно что-то другое. В какой-то момент мне пришла в голову “гениальная” идея - отзеркалить парус сменой координаты скалирования на отрицательное значение. Но тут тоже поджидала проблема, все объекты смещены относительно 0 согласно их размещению на корабле. Соответственно пропуская парус “через зеркало”, менялось и его положение.

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

World Position Offset и текстура паруса

В прошлой статье я рассказывал что с помощью этого параметра можно имитировать функциональность WindStrength, но из-за неудобств в использовании решил от этого отказаться. В общем-то ничего не изменилось, но мне хотелось добавить на паруса что-то типа эффекта ряби от ветра, и как раз для такой простой задачи эта функциональность замечательно подходит. Но у нас остается проблема с тем, что парус трясет даже в спущенном состоянии, и мне не хотелось исправлять это путем смены текстуры на вариант без этой анимации в рантайме. Ведь тогда это будет выглядеть рвано и не так впечатляюще. Поэтому я решил снова пересмотреть видео от UE по прототипированию парусников. И да! Там был ответ, и ответ этот - Material Parameter Collection. Задаешь его значение в Blueprint, получаешь значение в текстуре, все счастливы!

Счастливы по крайней мере до того, как не понимают, что данная коллекция применяется ко всем парусам, а не к конкретному. И вот тут мы возвращаемся к тому, зачем нам создание и установка на модели парусов Dynamic Instance Material, вместо того чтобы просто прописать материал в параметрах ассета. Дело в том, что для каждого конкретного инстанса можно прописывать уникальные параметры для материала в рантайме. Но это можно сделать только если хранить ссылку на этот инстанс в памяти. Через простой Get Material от ассета нужного объекта получить не получиться, даже Cast To завершается ошибкой. Вот как это реализовано у меня:

Разработка ремейка методами чайника. Часть 5

Таким образом, когда производятся операции с парусами, я получаю ссылку на динамический материал из сохраненной переменной и модифицирую параметр-мультипликатор в текстуре. А вот собственно как выглядит логика текстуры:

Разработка ремейка методами чайника. Часть 5

Итог

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

Тартана
Бригантина

Я думаю паруса получились весьма неплохо для такого чайника как я. В оригинальной игре у четырехугольных парусов есть неприятный резкий переход между состояниями, я же попытался сделать все максимально плавно. Еще предстоит много работы над тем, чтобы реализовать инерцию от поворотов, влияния веса, стабильность судна на воде и так далее, но это в будущем. К следующей статье я планирую заняться логикой пушек, чтобы добавить немного “экшона” в этот, пока еще пустой, мир. Если к тому моменту клятая простуда меня не добьет конечно…

Если вам понравилась статья, то буду благодарен за ваши комментарии, вопросы или советы!

5.8K5.8K показов
749749 открытий
7 комментариев

Комментарий недоступен

Ответить

Автор большой молодец. Серия статей отличная, хотя многие технические детали я не понимаю.

Но есть одно НО, которое меня гложет...

Очень интересует какой у Вас был опыт в разработке и 3D моделировании до того как вы решили заняться этим ремейком?

Я сам веб-разработчик(далеко не джун) и когда сел за Unity то утонул просто в интерфейсе и количестве новой информации. В первые 30 минут правильно подвинуть объект на сцене было проблемой, дальше взял курсы и базовые туториалы, но пока не хватает мотивации что-то довести до конца.

При этом в первой статье Вы написали "Т.к. у меня есть опыт в программировании, хоть и не в геймдеве, но я как минимум что-то должен смочь сделать." и есть ощущение что вы где-то лукавите. Либо у вас затяжной отпуск и вы имеете возможность тратить очень много времени на изучение UE, Blender и всех сопутствующих вещей.

У вас уже в пятой статье реализация физики тканей, как-то умудряетесь что-то моделировать в блендере. Я же в блендере максимум что мог это пересохранить модель в нужном мне формате.

Поделитесь вашим изначальным опытом когда брались за проект и сколько времени на него уходит?

Ответить

Спасибо за комментарий!

Я так-то тоже веб-разработчик. Профессионально кожу уже лет 7, + еще лет 5 любительски. С игровыми движками опыта я никогда не имел, собственно как и с 3д моделированием. Если бы имел, столько страданий мне это бы не доставляло...

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

Вы глубоко заблуждаетесь думая, что я шарю за блендер или UE. Всю свою разработческую жизнь я изучал только ту часть, которую мне нужно реализовать. Вот собственно и в блендере, я целенаправленно искал что-то типа физики ткани, сохранения деформации, кости, начал это применять. А так я ничего толкового не намоделирую. Дилетант кароч говоря.

Мне довольно сложно сказать сколько я трачу времени на проект... разработка выглядит весьма хаотично. Час я могу потратить на то, чтобы что-то для игры сделать. Потом отвлекусь и видосы в ютубе смотрю. Иногда попадаются видосы по анриалу связанные с моей текущей или будущей задачей. Считать ли это за время потраченное на проект?

В общем если отвечать абстрактно, то времени тратиться много. Я все таки тупой)

Ответить

Не знаю, будет ли развитие до полноценной игры или это чисто портфолио.
Сделай нормальную анимацию "заливания" палубы корабля. Просто проваливание под текстуру воды выглядит не очень.

Ответить

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

Эффекты с водой будут реализованы с помощью отдельного плагина. Пока что жду новой версии океанологии для этого.

Ответить