Делаю Unreal штуки. Бассейн. Часть вторая.
В первой части я рассказывал о том, как я делал поверхность бассейна для игры. Было много воды и картинок, но физику я решил вынести во вторую часть, так как поговорить есть о чём.
На создание бассейна у меня было два дня. Поэтому многие решения упрощались на ходу. Мне хотелось сделать так, чтобы плавающие предметы использовали физику движка, а не просто качались на волнах опираясь на контрольные точки на поверхности воды. Ну кого этим удивишь?
Принцип физики основан на силах выталкивания вверх и силе толкания в сторону (чтоб плыло). К этому я добавил дампинги, подавляющие избыточные вращения и придающие эффект сопротивления воды.
Первым, что я попытался сделать - это вычислять пересечение объёма меша с объёмом бассейна. И дальше работать с этим пересечением:
Хоть это и простой способ, но у него есть недостаток - предметы несимметричные. И пересечение было зачастую больше, чем объём, погруженный под воду. Это приводило к неправильным расчётам.
Тогда пришлось пойти на крайние меры. Я решил считать этот объём вручную, перебирая все вершины меша. Звучит, конечно, ужасно, но на деле всё более оптимистично. Берем вершины меша:
И дальше в цикле проверяем каждую, находится ли она в объёме басика. Если да, то учитываем её при расчёте объёма.
С этим уже можно работать. Хочу заметить, что для упрощения вычислений всей этой физики, используется не тот меш, который мы видим. А низкополигональный, но повторяющий форму. У него меньше вершин - быстрее считать.
Идея с лоу-поли мешем была отличная, но к сожалению её нигде не применяли, и в расчётах использовались почти всегда обычные хай-поли меши (есть только у уточки и надувного круга, и всё) :(
После того как объём найден я применяю к его центру стандартную физоидную силу:
PercentInside я вычисляю как соотношение объёма под водой к объёму меша. Правда, в этом случае я использую первый вариант объёма под водой (который чуть больше). Это приводит к некоторым малозаметным артефактам, но упрощение было продиктовано сроками. PushoutForce - это, по сути, плавучесть предмета.
Также я применяю боковую силу на основе вершин, которые НАД водой и с учётом нормалей поверхности воды под этими вершинами.
После применения этих двух сил мы получаем левитирующий в космосе объект с декорациями воды вокруг. Этого не достаточно для эффекта воды, нужны еще останавливающие силы. Вязкость, сопротивление. Для этого я использую динамический дампинг.
Дампинг - это такой параметр затухания движения. Он задается у меша в разделе физики.
Этот параметр замедления применяется постоянно, в каждом кадре. Но для воды так не подходит. Поэтому дампинг надо пересчитывать в каждом тике в соответствии с PercentInside (объём под водой). То есть чем глубже объект, тем больше сопротивления он испытывает.
Кроме того я разделяю вертикальный и XY дампинги. Вертикальный у меня зависит от объёма под водой, а XY нет. Это делает объект приятно плавающим на волнах, но тормозящим при плоском движении по воде.
Ну и пару слов о проблемах:
Самая большая проблема в рассинхроне физики и момента применения сил. Если FPS падает ниже 20, то это прям явно видно. Лечить такое надо согласованием тика физики и тика басика (настройка группы тика). Можно попробовать лечить таймером вместо тика.
При большом количестве неоптимизированных предметов FPS плачет и рыдает, но сделать ничего не может.
Напоследок скажу, что параметры плавучести, а также коэффициенты дампингов я задавал для каждого объекта свои. Сначала хотел рассчитывать как-то универсально, но понял, что потрачу на это много времени и это того не стоит. Проще было указать, что уточка плавает хорошо, а ящик плохо. И в продакшн.
На этом про басик всё. Удачи!