Как создать физический водопад 2D

8

Я пытаюсь создать водопад, который будет выглядеть как на первом изображении ниже (пожалуйста, посмотрите это видео, чтобы лучше понять, чего я хочу достичь) с физическими свойствами, чтобы он мог перемещаться вокруг объектов с коллайдерами (подобно второе изображение ниже). Хотя связанный водопад является 3D, я заинтересован в 2d реализации.

Обратите внимание, что объекты являются динамическими, а некоторые движутся часто, поэтому водопад должен менять форму каждого кадра. Объекты движутся медленно, либо перемещаясь в разные позиции, либо вращаясь. Как это может быть сделано?

введите описание изображения здесь

введите описание изображения здесь

OnlyCodeMatters
источник

Ответы:

13

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

Анимация каскадных водопадов

Каждый объект, который может блокировать водопад (объекты, на которых есть WaterCatcherсценарий в моем прототипе), имеет контурную сетку, охватывающую его периметр. (Это может быть автоматически сгенерировано заранее, используя форму коллайдера)

Эта контурная сетка отображает поток воды вдоль объекта. Я использую шейдер, чтобы clipвывести часть, которая находится под объектом. Я также отслеживаю левую и правую точки «ловли», где водопад приземляется на объект и течет влево или вправо соответственно, поэтому я могу clipвыделить часть, которая находится слева от правого водопада и справа от левого водопада.

Анимация, показывающая водную сетку

Тогда вертикальные падения - это просто базовые четырехъядерные примитивы, вытянутые до соответствующей длины. Я использую другой шейдер, чтобы прокрутить текстуру водопада над водопадом и затемнить ее сверху и снизу. Затем я наношу на систему частиц пены в точке удара, чтобы помочь покрыть смесь.

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

Закройте еще эффект водопада

На вершине у меня есть «корневой» водопад, чтобы начать что-то новое. Каждый кадр, после Update()запуска всех сценариев, чтобы перемещать вещи, запускается CircleCastвниз, чтобы увидеть, попадает ли его вода в что-нибудь. Если он ударяется о WaterCatcher, он говорит ему показать свою водную оболочку ниже по течению от точки попадания.

Я определяю «вниз по течению», используя нормальное попадание - если оно очень близко к вертикали или если входящий водопад охватывает грани, которые имеют наклон в обоих направлениях, то мы проливаем как влево, так и вправо.

У каждого WaterCatcherесть свой левый и правый водопад, который он включает и размещает на своем дальнем краю, если он проливается в этом направлении - в противном случае они остаются скрытыми. Эти водопады в свою очередь CircleCastобрушиваются вниз, чтобы найти то, на что они проливаются, и так далее ...

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

Фон, камни и текстуры вращающейся платформы через Кенни


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

// My wraparound geometry is build so the "x+" UV direction
// points "outward" from the object.
// Using derivatives, I can turn this into a vector in screen space.
// We'll use this below to clip out water hanging off the bottom.
float2 outward = float2(ddx(i.uv.x), ddy(i.uv.x));

// i.worldX is the worldspace x position of this fragment
// (interpolated from the vertex shader)

// _LeftX is a material property representing the worldspace x coordinate
// of the rightmost water flow that's spilling left,
// and _RightX the wold x of the leftmost water flow that's spilling right.
float left = _LeftX - i.worldX;   // +ve if we're to the left of a left spill.
float right = i.worldX - _RightX; // +ve if we're to the right of a right spill.

float limit = max(left, right); // +ve if we're in the path of either flow.

// If the "outward" vector is pointing down, make this negative.
limit = min(limit, outward.y + 0.001f);

// If any of the conditions above make limit <= 0, abort this fragment.
clip(limit);

// Otherwise, scroll the water texture!
// Counter-clockwise if we're in the left flow, clockwise otherwise.
i.uv.y -= sign(left) * _Time.y;
Д.М.Григорий
источник
Это замечательно. Есть ли у вас планы предоставить код здесь или на GitHub, чтобы сообщество могло внести свой вклад в улучшение? Если нет, пожалуйста, подумайте об этом.
Содержание
Таких планов в настоящее время нет. Изображения выше были созданы с быстрым и хакерским подтверждением концепции, а не как отдельный пакет, который подойдет для такого использования. Дай мне знать, если тебе понадобится рука, копирующая что-то из этого, и я могу рассказать тебе, что нужно.
DMGregory
Мне удалось создать частицы пены, но мне нужна помощь в создании шейдера воды и, во-вторых, обрезке шейдера воды вокруг фигур (WaterCatcher).
Сдерживание
Я добавил фрагмент кода шейдера, показывающий, как работает обтравочный шейдер.
DMGregory
@ DMGregory WoooW !!! Извините, давно не был здесь. Работал над другими вещами. Сейчас я
рассматриваю
1
  1. Вы можете деформировать сетку водопада при столкновении объектов, чтобы соответствовать требуемому шаблону коллайдера.

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

Я бы пошел с 1.

  • Но Mesh деформации процессора - это медленно, но может работать на вас.
  • Я бы использовал шейдеры для достижения этого - пример шейдера воды - сетка имеет такие эффекты, как будто она сталкивается с другими сетками, и это намного быстрее, чем методы раньше. Я предполагаю, что возможно сделать меш, чтобы остановить рендеринг в некоторой проецируемой форме - это то, что вам нужно сделать, чтобы сделать обычный шейдер воды, это сложно сделать, если вы не знакомы с шейдерами.

Нет простого решения с хорошей производительностью.

Результат системы частиц: (Для изменения значений мне пришлось ждать около 3-4 с, это медленно) Результат столкновения системы частиц

Candid Moon _Max_
источник
Альтернативой пункту 1, но может быть немного сложнее, является наличие вашей собственной системы «частиц», которая отбрасывает коллайдеры точек / сфер и соблюдает физику. И затем «просто» генерировать сетку на основе этих точек. почти как работает рендерер строк. Единственное, что нужно решить, - это как разделить точки, чтобы идти в 2 направлениях при столкновении с коллайдером, как на скриншоте. Но не думайте, что это должно быть сложно. ИЛИ вы можете просто разместить точки статически и провести линию между ними. Я просто нужен красивый шейдер.
Сидар
@ Сидар Да, интересный подход. Одним из методов также может быть создание нескольких рендеров трасс и перемещение их относительно точки разделения. И проверять наличие столкновений с помощью некоторого компонента коллайдера - но это всего лишь обходной путь.
Candid Moon _Max_
В любом случае, если OP не хочет устанавливать его вручную, данные должны быть динамическими или статически запеченными. Интересно, вы могли бы использовать обычную систему частиц с включенным столкновением, а затем приблизиться между точками, чтобы нарисовать четырехугольную полосу. Количество частиц не должно быть высоким для этого.
Сидар
Разве это не на частицу? Я думаю, что в зависимости от стиля, который вы выберете, это может работать довольно хорошо.
Сидар