¿Cómo implementar este tipo de ondas con un sombreador de fragmentos GLSL?

11

Así que ya he implementado la parte de reflexión:

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

fuente

Ahora la pregunta es ¿cómo se implementan estas ondas?

cepro
fuente
3
Esta no es una respuesta completa, sino una serie de sugerencias: necesita un uniforme para "animar" el efecto, es decir, una variable similar al tiempo. Con ese timevalor, puede desplazar el uv.xycon un (sin(time),cos(time))vector de desplazamiento. Por supuesto, debe averiguar las amplitudes de las compensaciones de seno y coseno. Comenzaría con solo compensar el uv.yprimero y ver cómo puedo ajustar aún más el efecto.
teodron
Muchas gracias por estos consejos. Resultó que esto es lo que necesito después de probar la implementación de @ LeFauve.
cepro

Respuestas:

11

Traté de implementar lo que teodron sugirió:

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

Se ve bastante cerca (es difícil saberlo sin la imagen base) pero puede ajustar los parámetros.

Puede verlo en acción allí: https://www.shadertoy.com/view/Xll3R7

Algunas observaciones:

  • Tuve que invertir la coordenada y ya que estaba poniendo la imagen al revés, pero puede depender de lo que pase a la resolución.xy; si el resultado se invierte para usted, simplemente desinvierta uv.y
  • Cambié tus declaraciones de uniformes para que funcione con sombreado. Puedes ignorar esos cambios.
  • Sin embargo, deberá agregar un uniforme que proporcione el tiempo y usarlo en lugar de iGlobalTime (que es el tiempo en segundos)
  • Agregué un efecto de marea, ya que parece que hay uno en su ejemplo, pero es difícil saberlo (ver la variable sepoffset). Puedes eliminarlo si no te gusta
  • Eliminé el color superpuesto ya que no se veía bien, y su ejemplo no tenía uno
  • Para ajustar el efecto a tu gusto:
    • cambie el factor de iGlobalTime para acelerar / ralentizar el efecto (puede cambiar cada uno de ellos por separado si lo desea, digamos acelerar el movimiento x y ralentizar el movimiento y)
    • cambiar el factor cos () para amplificar / atenuar el efecto

EDITAR: cambié el desplazamiento para incluir la modificación de @cepro

LeFauve
fuente
1
¡Gran esfuerzo! +1
teodron
3
Gracias por tu ayuda :). Esto realmente da un resultado bastante cercano. Pero creo que se pierde un último ingrediente. Observe, en la imagen, que cuanto más cerca están esas ondas de la cámara (parte inferior de la pantalla), más grandes son (estiradas verticalmente). Entonces, ¿quizás necesitemos escalar el desplazamiento y por el uv.y? float yoffset = ((0.3 - uv.y) /0.3) * 0.05 * (1.0 + cos (iGlobalTime * 3.0 + 50.0 * uv.y)) ;. He intentado esto y me gusta el resultado.
cepro
Buena captura para las ondas más cercanas @cepro. Me lo perdí
LeFauve
En mi opinión, hay algo mal con la ola modificada pettern. Si bien las olas aumentan para mí, tienen ese extraño patrón "reflejado" (GTX 680 en el último Chrome).
Mario