Jak zaimplementować tego rodzaju fale za pomocą modułu cieniującego fragmenty GLSL?

11

Więc wdrożyłem już część refleksji:

uniform sampler2D texture;
uniform vec2 resolution;
uniform vec3 overlayColor;

void main()
{
vec2 uv = gl_FragCoord.xy / resolution.xy;

if (uv.y > 0.3)// is air - no reflection or effect
{
    gl_FragColor = texture2D(texture, vec2(uv.x, uv.y));
}
else
{
    // Compute the mirror effect.
    vec4 color = texture2D(texture, vec2(uv.x, 0.6 - uv.y));
    // 
    vec4 finalColor = vec4(mix(color.rgb, overlayColor, 0.25), 1.0);
    gl_FragColor = finalColor;
}
}

źródło

Teraz pytanie brzmi: jak te fale są wdrażane?

cepro
źródło
3
To nie jest pełna odpowiedź, ale seria podpowiedzi: potrzebujesz munduru, aby „ożywić” efekt - tj. Zmiennej podobnej do czasu. Za pomocą tej timewartości można przesunąć wektor uv.xyza pomocą (sin(time),cos(time))wektora przesunięcia. Oczywiście musisz ustalić amplitudy przesunięć sinus i cosinus. Zacznę od przesunięcia uv.ypierwszego i zobaczę, jak mogę dalej dostosować efekt.
teodron
Dziękuję bardzo za te wskazówki. Okazało się, że tego właśnie potrzebuję po wypróbowaniu implementacji @ LeFauve.
cepro

Odpowiedzi:

11

Próbowałem zaimplementować to, co sugeruje teodron:

void main()
{
    vec2 uv = gl_FragCoord.xy / resolution.xy;
    float sepoffset = 0.005*cos(iGlobalTime*3.0);
    if (uv.y > 0.3 + sepoffset)// is air - no reflection or effect
    {
        gl_FragColor = texture2D(texture, vec2(uv.x, -uv.y));
    }
    else
    {
        // Compute the mirror effect.
        float xoffset = 0.005*cos(iGlobalTime*3.0+200.0*uv.y);
        //float yoffset = 0.05*(1.0+cos(iGlobalTime*3.0+50.0*uv.y));
        float yoffset = ((0.3 - uv.y)/0.3) * 0.05*(1.0+cos(iGlobalTime*3.0+50.0*uv.y));
        vec4 color = texture2D(texture, vec2(uv.x+xoffset , -1.0*(0.6 - uv.y+ yoffset)));
        // 
        //vec4 finalColor = vec4(mix(color.rgb, overlayColor, 0.25), 1.0);
        gl_FragColor = color;
    }
}

Wygląda dość blisko (trudno powiedzieć bez obrazu podstawowego), ale można dostosować parametry.

Możesz zobaczyć to w akcji: https://www.shadertoy.com/view/Xll3R7

Kilka uwag:

  • Musiałem odwrócić współrzędną y, odkąd otrzymywałem obraz do góry nogami, ale może to zależeć od tego, co podasz do rozdzielczości. Xy; jeśli wynik jest dla ciebie odwrócony, po prostu cofnij uv.y
  • Zmieniłem twoje jednolite deklaracje, więc działa z shadertoy. Możesz zignorować te zmiany.
  • Konieczne będzie jednak dodanie munduru określającego czas i użycie go zamiast iGlobalTime (czyli czasu w sekundach)
  • Dodałem efekt pływów, ponieważ wygląda na to, że jest taki na twoim przykładzie, ale trudno powiedzieć (patrz zmienna sepoffset). Możesz go usunąć, jeśli ci się nie podoba
  • Usunąłem kolor nakładki, ponieważ nie wyglądał dobrze, a twój przykład go nie miał
  • Aby dostosować efekt do własnych upodobań:
    • zmień współczynnik iGlobalTime, aby przyspieszyć / spowolnić efekt (możesz zmienić każdy z nich osobno, jeśli chcesz, powiedzmy, przyspiesz ruch x i spowolnij ruch y)
    • zmień współczynnik cos (), aby wzmocnić / osłabić efekt

EDYCJA: Zmieniłem yoffset, aby uwzględnić modyfikację z @cepro

LeFauve
źródło
1
Wielki wysiłek! +1
teodron
3
Dziękuję za pomoc :). To naprawdę daje całkiem bliski wynik. Ale myślę, że brakuje mu ostatniego składnika. Zwróć uwagę na zdjęciu, że im bardziej te zmarszczki są bliżej aparatu (u dołu ekranu), tym większe są (pionowo rozciągnięte). Więc może musimy przeskalować przesunięcie y o UV? float yoffset = ((0,3 - uv.y) / 0,3) * 0,05 * (1,0 + cos (iGlobalTime * 3,0 + 50,0 * uv.y)); Próbowałem tego i podoba mi się wynik.
cepro
Dobry połów dla bliższych zmarszczek @cepro.
Straciłem
IMO coś jest nie tak z petternem ze zmodyfikowaną falą. Podczas gdy fale rosną dla mnie, mają w sobie ten dziwny „lustrzany” wzór (GTX 680 w najnowszym Chrome).
Mario,