Как оживить абстрактную текстуру воды 2d сверху вниз?


24

В настоящее время я реализую игру с видом сверху на океан. Я использую следующую небольшую абстрактную текстуру:введите описание изображения здесь

Фактическая текстура прозрачна, я добавил зеленый цвет для ясности.

Теперь у меня проблема в том, что я не знаю, как анимировать эту текстуру, чтобы вода выглядела хорошо. Я попытался переместить текстуру синусоидальной волной: texture.y += sin(angle) . Конечно, теперь вся текстура движется, что выглядит нереально. Следующее, что я попробовал, это добавить еще один слой и реализовать эффект параллакса. Так что отражения под поверхностью воды также будут двигаться, но намного медленнее. Это выглядит немного лучше, но все еще не ... достаточно хорошо.

Я думаю, что лучше всего будет выглядеть анимация, если отдельные ячейки будут расширяться и сжиматься, как сеть или кусок ткани. Представьте, что кто-то слегка потянет за одну вершину этих ячеек, и соседняя ячейка расширится, и ячейка, к которой я стремлюсь (или подтолкну), сократится. Вроде как паутина пружин (?). Но я понятия не имею, как реализовать что-то вроде этого:

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

(Я также открыт для различных идей / ответов о том, как оживить данную текстуру. Реализм здесь не главное, просто приятные на вид воды, похожие на движения ...)

Решение от DMGregory

В этом посте я опубликовал пример libgdx: 2d анимация воды неровная и не плавная (см. Ответ о фильтрации текстур)

Ответы:


41

Обычный способ сделать это - использовать косвенный поиск текстур в шейдере, чтобы исказить текстуру дисплея:

Анимированный GIF, показывающий анимацию воды

Здесь я использую текстуру с некоторыми низкочастотными цветовыми шумами (сглаживание сглаженных пятен случайных цветов) и прокручиваю ее по геометрии дисплея с течением времени.

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

Вместо того, чтобы рисовать цвета из этой текстуры, я беру красные и зеленые каналы и вычитаю их, 0.5fчтобы превратить их в псевдослучайный двухмерный вектор, который плавно меняется во времени и пространстве.

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

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

В Unity шейдер будет выглядеть следующим образом - он должен быть достаточно простым для перевода на язык шейдера по вашему выбору:

fixed4 frag (v2f i) : SV_Target
{               
    float2 waveUV = i.uv * _NoiseScale;
    float2 travel = _NoiseScrollVelocity * _Time.x;

    float2 uv = i.uv;
    uv += _Distortion * (tex2D(_Noise, waveUV + travel).rg - 0.5f);
    waveUV += 0.2f; // Force an offset between the two samples.
    uv += _Distortion * (tex2D(_Noise, waveUV - travel).rg - 0.5f);

    // Sample the main texture from the distorted UV coordinates.
    fixed4 col = tex2D(_MainTex, uv);

    return col;
}

1
Это выглядит действительно красиво. Я не уверен, что понимаю все атрибуты: _NoseScale = скаляр для масштабирования «карты шума». _NoiseScrollVelocity = Vector2, с какой скоростью мы движемся по карте шума. _Noise =? _Distortion = Скалярное Я выбираю в качестве фактора искажения? v2f = вершина мы определяем цвет. я =?
— morpheus05

_Noiseэто [текстурный сэмплер, который читает из] маленькой потертой случайной текстуры выше. v2f iэто интерполированные данные из вершинного шейдера - в основном мы используем его , чтобы получить координаты текстуры для пикселя мы рисуем, i.uv. И вы абсолютно правы во всем остальном.
— DMGregory

Я реализовал шейдер, и почему-то он не работает (он не двигается или искажения слишком велики), я полагаю, что неправильно установил значения. время = разница с последним кадром в мс. noise_scale = 1 (я использую вашу текстуру, повтор режима обтекания) noise_scroll_velocity = [0,01, 0,01] искажение = 0,02
— morpheus05

Обратите внимание, что переменная называется Time, а не DeltaTime. Если вы используете разницу во времени, и ваша частота кадров является постоянной, то вы всегда будете получать одно и то же число, и вы будете повторно запускать шейдер с теми же входами, получая одинаковый вывод (ничего не двигается). Хуже того, если ваша частота кадров непоследовательна, вы получите вибрацию туда-сюда. Вы хотите, чтобы общее время истекло, а не дельта время.
— DMGregory

Вскоре я нажал кнопку «Отправить», и я понял, что теперь это почти работает. Анимация, кажется, вызывает волны из нижнего правого угла, и примерно через 10 секунд она просто затухает, как волны, которые останавливаются. Что может быть причиной этого?
— morpheus05

6

Это называется эффектом каустики, и генерация этих эффектов во время выполнения довольно трудоемка, поэтому это традиционно делается с помощью предварительно визуализированной покадровой анимации. Существуют инструменты, которые будут генерировать кадры каустической анимации для вас, например, Caustics Generator , у которого есть бесплатная версия для некоммерческого использования. Есть также некоторые готовые, которые вы можете купить за значительно более дешевую, чем профессиональная версия инструмента, о котором я говорил.

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


Это очень интересно, я также посмотрю на этот генератор (хотя я попробую вариант с шейдером, если я его понимаю ...)
— morpheus05

4

Это похоже на текстуру, которую вы можете сгенерировать из графа вороной, например:

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

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


4
В прошлом я действительно отображал каустику в шейдере. Это не обязательно так дорого, как вы думаете ( вот пример рендеринга ребер Вороного в реальном времени в шейдере WebGL ), хотя получить правильную плавную форму по краям, а не заостренные многоугольники, может быть непросто.
— DMGregory

Ооо, это очень мило; У меня есть несколько генераторов местности, для которых это было бы очень удобно.
— FacticiusVir

0

Существует метод oldschool, включающий нижний слой текстуры и две полупрозрачные текстуры для отражения сверху.

Если вы хотите пройти весь путь и хотите, чтобы вода не выглядела полной клонированных волн или голубоватых суповых карт, то вам нужно достичь цели.

https://steamcdn-a.akamaihd.net/apps/valve/2010/siggraph2010_vlachos_waterflow.pdf


3
Хотя ссылки могут помочь, они никогда не дают хороших ответов. Не могли бы вы расширить оба эти тезисов? Как бы это осуществить?
— Vaillancourt

Первый метод, по сути, очень старый метод, используемый для анимации воды - вы берете текстуру воды базового слоя, координаты UVW которой смещены в направлении по вашему выбору. Теперь вы дополнительно применяете обычную карту / карту рельефа, которую вы перемещаете в другом направлении - если все сделано хорошо, это выглядит убедительно для небольших рек. Это очень ограничено, хотя для больших водоемов - как что-либо, напоминающее волну, получит эффект муара. Ссылка объясняет использование потоковых карт намного лучше, чем я мог.
— Пика

Пожалуйста, используйте функцию редактирования, чтобы улучшить вопрос с тем, что вы добавили здесь :) Люди привыкли искать ответы в посте, а не в комментариях.
— Vaillancourt
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.