Jak animować abstrakcyjną teksturę 2d z góry na dół?

24

Obecnie wdrażam grę z widokiem z góry na ocean. Używam następującej, trochę abstrakcyjnej tekstury:wprowadź opis zdjęcia tutaj

Faktyczna tekstura jest przezroczysta, dla jasności dodałem zielony kolor.

Problem, który mam teraz, polega na tym, że nie wiem, jak ożywić tę teksturę, aby woda wyglądała ładnie. Próbowałem przesunąć teksturę z falą grzech texture.y += sin(angle). Oczywiście teraz cała tekstura się porusza, co wygląda trochę nierealnie. Następną rzeczą, którą próbowałem, jest dodanie kolejnej warstwy i wdrożenie efektu paralaksy. Aby odbicia pod powierzchnią wody również się poruszały, ale znacznie wolniej. Wygląda trochę lepiej, ale wciąż nie ... wystarczająco ładnie.

Myślę, że najlepiej wyglądającą animacją byłoby, gdyby pojedyncze komórki rozszerzyły się i skurczyły, coś w rodzaju sieci lub kawałka materiału. Wyobraź sobie, że ktoś lekko pociągnąłby za jeden wierzchołek tych komórek, a sąsiadująca komórka rozszerzyłaby się, a komórka, do której pociągam w kierunku (lub naciskałem), kurczyłaby się. Coś jak sieć sprężyn (?). Ale nie mam pojęcia, jak zaimplementować coś takiego:

  • Jaki jest do tego model matematyczny? Coś ze sprężynami, gdzie siły pchają / ciągną?
  • A jeśli tak, to jak zmapować ten model do podanej tekstury? Trzymając wszystkie krzywe, a co nie ...

(Jestem również otwarty na różne pomysły / odpowiedzi na temat animowania danej tekstury. Realizm nie jest tutaj o tyle, tylko ładnie wyglądająca woda jak ruchy ...)

Rozwiązanie z DMGregory

W tym poście zamieściłem przykład libgdx: animacja wody 2d jest postrzępiona i nie jest gładka (zobacz odpowiedź na temat filtrowania tekstur)

morpheus05
źródło

Odpowiedzi:

41

Częstym sposobem jest to, używając pośredniego wyszukiwania tekstur w module cieniującym, aby zniekształcić teksturę wyświetlania:

Animowany gif przedstawiający animację wody

Tutaj używam tekstury z szumami kolorów o niskiej częstotliwości (układanie gładkich plam losowych kolorów) i przewijanie jej wzdłuż geometrii wyświetlacza w czasie.

wprowadź opis zdjęcia tutaj

Zamiast rysować kolory z tej tekstury, zamiast tego biorę czerwony i zielony kanał i odejmuję, 0.5faby przekształcić je w pseudolosowy wektor 2D, który zmienia się płynnie w czasie i przestrzeni.

Następnie mogę dodać niewielką wielokrotność tego wektora do moich współrzędnych UV, przed pobraniem próbki z głównej tekstury wody. To zmienia część tekstury, którą czytamy i wyświetlamy, wypaczając ją.

Uśredniając dwie próbki z tego szumu, przewijając w przeciwnych kierunkach, możemy ukryć kierunek ruchu, aby wyglądał jak bezcelowe cofanie się.

W Unity moduł cieniujący wyglądałby tak - powinien być wystarczająco prosty do przetłumaczenia na wybrany język modułu cieniującego:

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;
}
DMGregory
źródło
1
To wygląda naprawdę ładnie. Nie jestem pewien, czy rozumiem wszystkie atrybuty: _NoseScale = skalar do skalowania „mapy szumów”. _NoiseScrollVelocity = Vector2, z jaką prędkością poruszamy się po mapie hałasu. _Noise =?. _Distortion = Skalarny Wybieram jako czynnik zniekształceń? v2f = Wierzchołek określamy kolor. ja =?
morpheus05
_Noiseto [próbnik tekstur, który czyta z] małą, losową teksturę powyżej. v2f ijest interpolowane dane z vertex shader - głównie za jego pomocą uzyskać współrzędne tekstury dla piksela jesteśmy rysunku i.uv. I masz całkowitą rację co do całej reszty.
DMGregory
Zaimplementowałem moduł cieniujący i jakoś nie działa (nie porusza się lub zniekształcenie jest za duże), zakładam, że nie ustawiłem poprawnie wartości. czas = różnica od ostatniej klatki w ms. noise_scale = 1 (używam twojej tekstury, powtarzaj tryb zawijania) noise_scroll_velocity = [0,01, 0,01] zniekształcenie = 0,02
morpheus05
Zauważ, że zmienna nosi nazwę Czas, a nie DeltaTime. Jeśli użyjesz różnicy czasu, a liczba klatek na sekundę będzie stała, zawsze otrzymasz tę samą liczbę i ponownie uruchomisz moduł cieniujący z tymi samymi wejściami, uzyskując tę ​​samą moc wyjściową (nic się nie rusza). Co gorsza, jeśli liczba klatek na sekundę jest niespójna, wówczas pojawi się wibracja tam iz powrotem. Chcesz, aby upłynął całkowity czas, a nie czas delta.
DMGregory
Wkrótce uderzyłem w send, zdałem sobie sprawę z tego i teraz prawie działa. Animacja wydaje się wyłapywać fale z prawego dolnego rogu, a po około 10 sekundach znika, jak fale, które się zatrzymują. Co mogłoby być tego przyczyną?
morpheus05
6

Nazywa się to efektem kaustycznym, a generowanie tych efektów w czasie wykonywania jest dość czasochłonne, więc tradycyjnie odbywa się to za pomocą wstępnie renderowanej animacji klatka po klatce. Istnieją narzędzia, które wygenerują dla Ciebie żrące klatki animacji, takie jak Caustics Generator , który ma bezpłatną wersję do użytku niekomercyjnego. Istnieje również kilka gotowych, które można kupić za znacznie tańsze niż pro wersja wspomnianego narzędzia.

Pamiętaj, że efekty żrące są również zwykle efektem stosowanym jako lekkie ciastko na podwodnym terenie lub na podwodnej powierzchni. Oznacza to, że umieszczenie go na powierzchni wody podczas patrzenia w dół nie jest zwykle tym, jak wygląda woda.

Ed Marty
źródło
To bardzo interesujące, przyjrzę się również temu generatorowi (choć zdarzę, wypróbuję wariant modułu cieniującego, jeśli go rozumiem ...)
morpheus05
4

Wygląda to na teksturę, którą można wygenerować z wykresu voronoi, np .:

wprowadź opis zdjęcia tutaj

Możesz dokonywać drobnych, płynnych korekt na wykresie, przesuwając punkty; ponownie rysując wykres, każda klatka byłaby dość droga, więc prawdopodobnie zechcesz wstępnie renderować animację.

FacticiusVir
źródło
4
W przeszłości renderowałem w ten sposób środki kaustyczne w module cieniującym. To niekoniecznie tak drogie, jak mogłoby się wydawać ( oto przykład renderowania krawędzi Voronoi w czasie rzeczywistym w module cieniującym WebGL ), chociaż uzyskanie odpowiedniego gładkiego kształtu na krawędziach - a nie spiczastych wielokątów - może być trudne.
DMGregory
Ooo, to bardzo miłe; Mam kilka generatorów terenu, dla których byłoby to bardzo przydatne.
FacticiusVir
0

Istnieje metoda oldschoolowa, obejmująca dolną warstwę tekstury i dwie półprzezroczyste tekstury do odbicia na górze.

Jeśli chcesz przejść całą drogę i nie chcesz, aby woda nie wyglądała na pełną sklonowanych fal lub samish niebieskich zup - mapy przepływu są celem.

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

Cycero
źródło
3
Chociaż linki mogą pomóc, nigdy nie dają dobrych odpowiedzi. Czy możesz rozwinąć obie te metody? Jak pójść o jego wdrożeniu?
Vaillancourt
Pierwsza metoda jest w zasadzie bardzo starą metodą animacji wody - bierzesz teksturę wody warstwy podstawowej, której współrzędne UVW zostają przesunięte w wybranym kierunku. Teraz stosujesz dodatkowo normalną mapę / mapę wypukłości, którą przesuwasz w innym kierunku - jeśli zrobisz to dobrze, wygląda to przekonująco dla małych rzek. Jest to bardzo ograniczone w przypadku dużych zbiorników wodnych - ponieważ wszystko przypominające fale uzyska efekt mory. Link wyjaśnia użycie map przepływów znacznie lepiej niż mogłem.
Pica,
Użyj funkcji edycji, aby poprawić pytanie dodając tutaj :) Ludzie są przyzwyczajeni do szukania odpowiedzi w poście, a nie w komentarzach.
Vaillancourt