Как я делаю Unreal штуки. Бассейн. Часть первая.
В одной игре мне надо было сделать бассейн, в который можно бросать предметы. Ну, тема тёртая, но захотелось не копипастить и сделать физику в воде. И вот как это было:
Суть.
Бассейн состоит из двух базовых вещей - поверхность воды и физика воды. Понятно, что есть еще подповерхность, но в нашей игре камера тудой не ныряла, так что в сути не участвовала.
Значится, поверхность я решил делать процедурным мешем, чтоб волны пускать, как нормальный человек. К тому же хотелось чтоб волны толкали плавающие предметы. Плюс к этому материал, который симулирует ветер. А физику хотелось сделать так, чтоб не стыдно было (хотя потом пару раз было стыдно).
Идея.
Если с поверхностью всё более-менее понятно - берешь любой простой алгоритм расчета волн и двигаешь точки (о нём – чуть пизже), А вот с физикой было не очень понятно. Ведь физика в анриле и так есть, но она не водная. Если физику отключить и двигать объект туда-сюда самому, то на физику это не будет похоже.
Так что идея была такая - сымитировать выталкивание предмета из воды (то есть в каждом тике толкать его импульсом вверх) взяв за основу вершины меша, находящиеся под водой, и учитывая объем, который под водой оказался.
В этой части расскажу про поверхность, а во второй про физику.
Итак, поверхность воды это простой прямоугольный меш с достаточным количеством вершин для сглаживания. Сам меш я генерирую процедурно, используя для этого UProceduralMeshComponent. Грубо говоря в цикле создаю X * Y точек и соединяю их в треугольники.
Дальше, в таймере или тике я вызываю обновление всех вершин, которое заключается в выполнении алгоритма моделирования поверхности воды. Я взял самый простой, который нашел на просторах рунета, а именно этот:
Я взял его, потому, что, когда-то давно прочитал его в книжке, и реализовал шейдер воды на его основе. Тогда он показался мне очень красивым и натуральным. У него достаточно настроек, чтобы сымитировать разные жидкости. Книжки давно нет, так что оставалось только нагуглить его где-нибудь.
Тут идея простая: есть два массива вершин - текущий кадр и предыдущий кадр. Расчёт текущего кадра происходит на основе предыдущего, затем массивы меняются местами. Таким образом происходит эволюция поверхности. Затухание и распространение волн по ней.
Кроме расчета распространения волн, рассчитываются нормали для каждой вершины. Довольно грубым способом, но он дает хороший результат: разница высот между соседними точками по Х и по У отдельно.
Ну и осталось последнее - сделать возможность тыкать в воду. По сути тычок в воду это запись в массив вершин значения высоты в нужном месте. Для капли подойдет запись в один элемент, для тычка я закладывал в функцию еще размер тычка. То есть циклом проходился по вершинам и опускал их. Когда объект достаётся из воды, то он тыкает капельки под собой в таймере.
Поверх этого всего полернул материалом для симуляции ветра на поверхности (нормалками).
В следующей части распишу про поведение объектов в воде, про физику выталкивания и про возникшие проблемы.