Разработка ремейка методами чайника. Часть 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 открывать. Но статья уже затянулась и у меня истекает мой недельный дедлайн между статьями, поэтому я напоследок просто покажу что получилось:

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

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

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

36
7 комментариев

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

3
Ответить

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

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

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

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

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

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

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

1
Ответить

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

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

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

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

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

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

1
Ответить

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

1
Ответить

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

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

Ответить