Como implementar esse tipo de ondulações com um shader de fragmento GLSL?

11

Então, eu já implementei a parte da reflexão:

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

fonte

Agora, a pergunta é como essas ondulações são implementadas?

cepro
fonte
3
Esta não é uma resposta completa, mas uma série de dicas: você precisa de um uniforme para "animar" o efeito - ou seja, uma variável temporal. Usando esse timevalor, você pode mudar o uv.xycom um (sin(time),cos(time))vetor de deslocamento. Obviamente, você deve descobrir as amplitudes das compensações seno e cosseno. Eu começaria apenas compensando o uv.yprimeiro e ver como posso ajustar ainda mais o efeito.
Teodron
Muito obrigado por essas dicas. Acontece que é disso que eu preciso depois de tentar a implementação do @ LeFauve.
CEPRO

Respostas:

11

Tentei implementar o que o teodron sugeria:

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

Parece bem próximo (é difícil dizer sem a imagem de base), mas você pode ajustar os parâmetros.

Você pode vê-lo em ação lá: https://www.shadertoy.com/view/Xll3R7

Algumas observações:

  • Eu tive que inverter a coordenada y desde que estava obtendo a imagem de cabeça para baixo, mas isso pode depender do que você passa para o resolution.xy; se o resultado for invertido, basta desmarcar uv.y
  • Mudei suas declarações uniformes para que funcione com shadertoy. Você pode ignorar essas alterações.
  • No entanto, você precisará adicionar um uniforme, fornecendo o tempo e usá-lo no lugar do iGlobalTime (que é o tempo em segundos)
  • Adicionei um efeito de maré, pois parece que existe um no seu exemplo, mas é difícil dizer (consulte a variável sepoffset). Você pode removê-lo se não gostar
  • Eu removi a cor da sobreposição, pois ela não estava bonita e seu exemplo não tinha uma
  • Para ajustar o efeito ao seu gosto:
    • altere o fator do iGlobalTime para acelerar / desacelerar o efeito (você pode alterar cada um deles separadamente, se quiser, digamos, acelerar o movimento x e diminuir o movimento y)
    • altere o fator cos () para amplificar / atenuar o efeito

EDIT: Eu mudei o yoffset para incluir a modificação do @cepro

LeFauve
fonte
1
Grande esforço! +1
teodron
3
Obrigado pela ajuda :). Isso realmente dá um resultado bem próximo. Mas acho que falta um último ingrediente. Observe, na imagem, que quanto mais próximas essas ondulações estiverem da câmera (parte inferior da tela), maiores elas serão (esticadas verticalmente). Então, talvez precisamos escalar o deslocamento y pelo uv.y? yoffset de flutuação = ((0,3 - uv.y) / 0,3) * 0,05 * (1,0 + cos (iGlobalTime * 3,0 + 50,0 * uv.y)) ;. Eu tentei isso e eu meio que gosto do resultado.
CEPRO
Boa captura para as ondulações mais próximas @cepro. Eu perdi
LeFauve
Na IMO há algo errado com a onda modificada pettern. Enquanto as ondas aumentam para mim, elas têm um padrão "espelhado" estranho (GTX 680 no Chrome mais recente).
Mario