Controls

Text

Font Size (px)

Distortion

20.00

Refraction Width

75.00

Ripples

1.00

Sharpness (Bias)

5.6

Spacing

75.00

Aberration

2.5

Frosted (Blur)

0.75

Description

This shader is an exercise in simulating physical light refraction and surface properties. Instead of just "distorting" an image, we are modeling how light bends when passing through a variable-density medium like glass.

When light passes from air into glass, it changes speed and direction, a phenomenon described by Snell's Law. In 2D, we simulate this by "displacing" the texture coordinates. To know how much to displace, we model the surface as a series of concentric ripples, defined by a shaping function waveProfile:

float waveProfile(float dist, float r, float w, float b) {
    float d = abs(dist - r);
    float t = clamp(d / w, 0.0, 1.0);
    return pow(1.0 - t, b);
}

This function takes the current distance dist, the ring radius r, and controls for width w and sharpness b. A pow() function is used to create a sharp ridge or a soft rolling wave. Complex surfaces are then built by superposition—summing up multiple such rings in a loop:

float totalDisplacement = 0.0;
for (int i = 0; i < count; i++) {
    float r = float(i + 1) * spacing;
    totalDisplacement += waveProfile(dist, r, width, bias);
}

Once we have the scalar totalDisplacement "height", we convert it into a displacement vector offset by pushing pixels outward from the ripple center. This mimics the lens effect of the wave crest:

vec2 offset = dir * totalDisplacement * strength;
vec2 distUV = uv - offset;

Real glass also exhibits dispersion—where different colors bend at different angles. We simulate this chromatic aberration by splitting our texture lookup into three separate samples for Red, Green, and Blue, scaling the offset slightly differently for each:

float r = texture(tex, uv - offset * (1.0 + chroma)).r;
float g = texture(tex, uv - offset).g;
float b = texture(tex, uv - offset * (1.0 - chroma)).b;

Finally, to achieve a "frosted" look, we apply a 5x5 Box Blur kernel around our target coordinate, averaging the values to diffuse the light.