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