0.00
60.0 fps

Random bumpmap Mountains

cool

Log in to post a comment.

#version 300 es
precision highp float;

uniform float iTime;
uniform vec2 iResolution;
out vec4 fragColor;

// Hash & noise
float hash(vec2 p) {
    p = fract(p * vec2(123.4, 456.7));
    p += dot(p, p + 34.56);
    return fract(p.x * p.y);
}

float noise(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);
}

float fbm(vec2 p) {
    float t = 0.0;
    float amp = 0.5;
    for (int i = 0; i < 8; i++) {
        t += noise(p) * amp;
        p *= 2.0;
        amp *= 0.5;
    }
    return t;
}

float getHeight(vec2 p) {
    float base = fbm(p * 0.6);              // medium-scale terrain
    float fine = fbm(p * 2.5) * 0.15;       // small bumps

    float height = base * 3.0 + fine * 3.0;

    // Smooth lowlands: fade out detail if base is low
    float lowland = smoothstep(0.0, 0.6, height);
    return mix(base * 3.0, height, lowland);
}


vec3 getNormal(vec2 p) {
    float eps = 0.1;
    float h = getHeight(p);
    float hx = getHeight(p + vec2(eps, 0.0));
    float hy = getHeight(p + vec2(0.0, eps));
    return normalize(vec3(- (hx - h), - (hy - h), 1.0));
}

vec3 terrainColor(float height) {
    if (height > 2.3) return vec3(1.0);                    // snow
    else if (height > 1.6) return vec3(0.5, 0.5, 0.5);      // rock
    else return vec3(0.1, 0.5, 0.2);                        // grass
}

// Sky-projected clouds (directional)
vec3 skyWithClouds(vec3 rayDir, float time) {
    float elevation = rayDir.z;

    // Project rayDir to a 2D domain for clouds
    vec2 cloudUV = normalize(rayDir.xy) * 0.5 + vec2(0.5); // sphere to [0,1]
    cloudUV += vec2(time * 0.01, 0.0); // move clouds

    float cloud = fbm(cloudUV * 4.0); // denser clouds
    float clouds = smoothstep(0.5, 0.7, cloud);

    vec3 skyBase = vec3(0.6, 0.8, 1.0);
    vec3 cloudColor = mix(skyBase, vec3(1.0), clouds * smoothstep(0.0, 0.5, elevation));
    return cloudColor;
}

// Simulate forward movement with heading drift
vec2 getCameraPath(float time) {
    vec2 pos = vec2(0.0);
    float angle = 0.0;

    // Simulate small steering changes over time
    for (float t = 0.0; t < time; t += 0.1) {
        angle = 0.3 * sin(t * 0.07) + 0.15 * sin(t * 0.17); // same curve
        vec2 dir = vec2(cos(angle), sin(angle));
        pos += dir * 0.04; // speed * dt
    }

    return pos;
}

void main() {
    vec2 uv = (gl_FragCoord.xy / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;

    // ✨ Smoothly changing heading angle
   
   float headingAngle = 0.3 * sin(iTime * 0.07) + 0.15 * sin(iTime * 0.17);
    vec2 forwardDir = vec2(cos(headingAngle), sin(headingAngle));
    vec2 camPath = getCameraPath(iTime); // ✨ use integrated position

    // ✨ Always moving forward in current heading
    float speed = 0.4;


    vec3 camPos = vec3(camPath, 2.0);                       // eye height
    vec3 targetPos = vec3(camPath + forwardDir * 5.0, 1.4); // look slightly down

    vec3 camDir = normalize(targetPos - camPos);
    vec3 camRight = normalize(cross(vec3(0.0, 0.0, 1.0), camDir));
    vec3 camUp = cross(camDir, camRight);

    vec3 rayDir = normalize(camDir + uv.x * camRight + uv.y * camUp);
    vec3 rayPos = camPos;

    // Raymarch loop
    float t = 0.0;
    float maxDist = 100.0;
    bool hit = false;
    vec3 hitPos;
    float dist = 0.0;

    for (int i = 0; i < 64; i++) {
        vec3 pos = camPos + rayDir * t;
        float h = getHeight(pos.xy);
        dist = pos.z - h;

        if (dist < 0.0) {
            hit = true;
            hitPos = pos;
            break;
        }

        t += clamp(dist * 0.5, 0.01, 0.2); // smart step size
        if (t > maxDist) break;
    }

    vec3 color;

    if (hit) {
        float height = getHeight(hitPos.xy);
        bool isLake = height < 0.5;
        if (isLake) height = 0.5; // flatten lake

        vec3 baseColor = isLake
            ? vec3(0.1, 0.3, 0.6) // lake blue
            : terrainColor(height);

        vec3 normal = getNormal(hitPos.xy);
        vec3 lightDir = normalize(vec3(0.4, 0.5, 1.0));
        float diff = max(dot(normal, lightDir), 0.0);
        float spec = pow(max(dot(normal, normalize(lightDir + vec3(0.0, 0.0, 1.0))), 0.0), 64.0);

        vec3 surfaceColor = baseColor * diff + vec3(1.0) * spec * 0.3;

        float fogAmount = smoothstep(30.0, 80.0, t);
        vec3 skyColor = skyWithClouds(rayDir, iTime);
        color = mix(surfaceColor, skyColor, fogAmount);
    } else {
        // Ray didn't hit terrain — render sky with clouds
        color = skyWithClouds(rayDir, iTime);
    }

    fragColor = vec4(color, 1.0);
}