Как реализовать этот вид ряби с помощью фрагментного шейдера GLSL?

11

Итак, я уже реализовал часть отражения:

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

источник

Теперь вопрос в том, как реализованы эти колебания?

CEPRO
источник
3
Это не полный ответ, а ряд подсказок: вам нужна униформа для «оживления» эффекта - то есть переменная времени. С помощью этого timeзначения можно сместить uv.xyс (sin(time),cos(time))вектором смещения. Конечно, вы должны вычислить амплитуды синусов и косинусов. Я бы начал с простого смещения uv.yпервого и посмотрел, как я могу настроить эффект дальше.
Теодрон
Большое спасибо за эти подсказки. Оказалось, это то, что мне нужно после попытки реализации @ LeFauve.
Cepro

Ответы:

11

Я попытался реализовать то, что предложил теодрон:

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

Это выглядит довольно близко (трудно сказать без базового изображения), но вы можете настроить параметры.

Вы можете увидеть это в действии там: https://www.shadertoy.com/view/Xll3R7

Некоторые замечания:

  • Мне пришлось инвертировать координату y, так как я переворачивал изображение вверх ногами, но это может зависеть от того, что вы передаете в resolution.xy; если результат для вас инвертирован, просто удалите ув.
  • Я изменил ваши декларации об униформе, чтобы они работали с шадертой. Вы можете игнорировать эти изменения.
  • Однако вам нужно будет добавить униформу, предоставляющую время, и использовать ее вместо iGlobalTime (то есть времени в секундах).
  • Я добавил эффект прилива, так как он выглядит так, как будто он есть в вашем примере, но трудно сказать (см. Переменную sepoffset). Вы можете удалить его, если вам не нравится
  • Я удалил цвет наложения, так как он не очень хорошо выглядел, а в вашем примере его не было
  • Чтобы настроить эффект на свой вкус:
    • измените коэффициент iGlobalTime, чтобы ускорить / замедлить эффект (вы можете изменить каждый из них по отдельности, если хотите, скажем, ускорить движение x и замедлить движение y)
    • изменить коэффициент cos (), чтобы усилить / ослабить эффект

РЕДАКТИРОВАТЬ: я изменил yoffset, чтобы включить модификацию из @cepro

LeFauve
источник
1
Большое усилие! +1
теодрон
3
Спасибо за помощь :). Это действительно дает довольно близкий результат. Но я думаю, что это пропускает один последний ингредиент. Обратите внимание, что на снимке, чем ближе эти ряби к камере (нижняя часть экрана), тем больше они (растянуты по вертикали). Так что, может быть, нам нужно масштабировать смещение y по uv.y? float yoffset = ((0,3 - ув.у) / 0,3) * 0,05 * (1,0 + cos (iGlobalTime * 3,0 + 50,0 * ув.у)) ;. Я попробовал это, и мне нравится результат.
Cepro
Хороший улов для более близких пульсаций @cepro. Я пропустил это
LeFauve
ИМО что-то не так с модифицированным волновым петтерном. В то время как волны увеличиваются для меня, в них есть странный «зеркальный» рисунок (GTX 680 в последнем Chrome).
Марио