summaryrefslogtreecommitdiff
path: root/themes/src/_shaders/water.vert
blob: 7121ab19c9093ca61cabad74ea147b5bc75c8f0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
precision highp float;

attribute vec2 position;      // local (x, z) on the plane

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform float time;
uniform float amplitude;

varying vec3 vWorldPos;
varying vec3 vNormal;

float hash(vec2 p) {
    p = fract(p * vec2(123.34, 456.21));
    p += dot(p, p + 45.32);
    return fract(p.x * p.y);
}

float valueNoise(vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    float a = hash(i);
    float b = hash(i + vec2(1.0, 0.0));
    float c = hash(i + vec2(0.0, 1.0));
    float d = hash(i + vec2(1.0, 1.0));
    vec2 u = f * f * (3.0 - 2.0 * f);
    return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}

// Irregular height: non-harmonic directional sines plus two octaves of
// scrolling value noise so it never reads as a single clean wave.
float waveHeight(vec2 p, float t) {
    float h = 0.0;
    h += 0.30 * sin(dot(p, vec2(0.90, 0.30)) * 0.35 + t * 1.1);
    h += 0.20 * sin(dot(p, vec2(-0.40, 1.00)) * 0.55 - t * 1.7);
    h += 0.12 * sin(dot(p, vec2(0.70, -0.80)) * 0.90 + t * 2.3);
    h += 0.08 * sin(dot(p, vec2(1.00, 0.60)) * 1.60 - t * 3.1);
    h += 0.18 * (valueNoise(p * 0.25 + vec2(t * 0.15, t * 0.10)) - 0.5);
    h += 0.09 * (valueNoise(p * 0.70 - vec2(t * 0.20, 0.0)) - 0.5);
    return h;
}

void main() {
    vec2 p = position;
    float t = time;

    float h = waveHeight(p, t) * amplitude;

    // Analytic normal via central differences of the same height function.
    float e = 2.0;
    float hL = waveHeight(p - vec2(e, 0.0), t) * amplitude;
    float hR = waveHeight(p + vec2(e, 0.0), t) * amplitude;
    float hD = waveHeight(p - vec2(0.0, e), t) * amplitude;
    float hU = waveHeight(p + vec2(0.0, e), t) * amplitude;
    vec3 N = normalize(vec3(hL - hR, 2.0 * e, hD - hU));

    vec4 worldPos = model * vec4(p.x, h, p.y, 1.0);
    vWorldPos = worldPos.xyz;
    vNormal   = N;   // model is translation-only, so no normal matrix needed

    gl_Position = projection * view * worldPos;
}