Wie implementiere ich diese Art von Wellen mit einem GLSL-Fragment-Shader?

11

Also habe ich den Reflexionsteil bereits implementiert:

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;
}
}

Quelle

Die Frage ist nun, wie diese Wellen implementiert werden.

cepro
quelle
3
Dies ist keine vollständige Antwort, sondern eine Reihe von Hinweisen: Sie benötigen eine Uniform, um den Effekt zu "animieren" - dh eine zeitähnliche Variable. Mit diesem timeWert können Sie den uv.xymit einem (sin(time),cos(time))Versatzvektor verschieben. Natürlich müssen Sie die Amplituden der Sinus- und Cosinus-Offsets herausfinden. Ich würde damit beginnen, nur den uv.yersten zu versetzen und sehen, wie ich den Effekt weiter anpassen kann.
Teodron
Vielen Dank für diese Hinweise. Es stellte sich heraus, dass dies das ist, was ich brauche, nachdem ich die Implementierung von @ LeFauve ausprobiert habe.
Cepro

Antworten:

11

Ich habe versucht umzusetzen, was Teodron vorgeschlagen hat:

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;
    }
}

Es sieht ziemlich genau aus (ohne das Basisbild ist es schwer zu sagen), aber Sie können die Parameter anpassen.

Sie können es dort in Aktion sehen: https://www.shadertoy.com/view/Xll3R7

Einige Anmerkungen:

  • Ich musste die y-Koordinate invertieren, da ich das Bild auf den Kopf gestellt habe, aber es kann davon abhängen, was Sie in Resolution.xy übergeben. Wenn das Ergebnis für Sie invertiert ist, deaktivieren Sie einfach uv.y.
  • Ich habe deine einheitlichen Erklärungen geändert, damit es mit Shadertoy funktioniert. Sie können diese Änderungen ignorieren.
  • Sie müssen jedoch eine Uniform hinzufügen, die die Zeit angibt, und diese anstelle von iGlobalTime (dies ist die Zeit in Sekunden) verwenden.
  • Ich habe einen Gezeiteneffekt hinzugefügt, da es so aussieht, als gäbe es einen in Ihrem Beispiel, aber es ist schwer zu sagen (siehe Sepoffset-Variable). Sie können es entfernen, wenn es Ihnen nicht gefällt
  • Ich habe die Überlagerungsfarbe entfernt, da sie nicht gut aussah und Ihr Beispiel keine hatte
  • So optimieren Sie den Effekt nach Ihrem Geschmack:
    • Ändern Sie den Faktor von iGlobalTime, um den Effekt zu beschleunigen / zu verlangsamen (Sie können jeden von ihnen separat ändern, wenn Sie möchten, z. B. die x-Bewegung beschleunigen und die y-Bewegung verlangsamen).
    • Ändern Sie den cos () -Faktor, um den Effekt zu verstärken / abzuschwächen

BEARBEITEN: Ich habe den yoffset geändert, um die Änderung von @cepro aufzunehmen

LeFauve
quelle
1
Große Anstrengung! +1
Teodron
3
Danke für deine Hilfe :). Dies ergibt wirklich ein ziemlich nahes Ergebnis. Aber ich denke, es fehlt eine letzte Zutat. Beachten Sie im Bild, dass diese Wellen umso größer sind (vertikal gestreckt), je näher diese Wellen an der Kamera (unten auf dem Bildschirm) liegen. Vielleicht müssen wir also den y-Versatz um uv.y skalieren? float yoffset = ((0,3 - uv.y) / 0,3) * 0,05 * (1,0 + cos (iGlobalTime * 3,0 + 50,0 * uv.y));. Ich habe es versucht und das Ergebnis gefällt mir irgendwie.
Cepro
Guter Fang für die näheren Wellen @cepro. Ich habe es verpasst
LeFauve
IMO stimmt etwas mit dem modifizierten Wellenmuster nicht. Während die Wellen für mich zunehmen, haben sie dieses seltsame "gespiegelte" Muster (GTX 680 im neuesten Chrome).
Mario