cool
Log in to post a comment.
#version 300 es precision highp float; uniform float iTime; uniform vec2 iResolution; const float waterLevel = 120.0; out vec4 fragColor; const float hillMax = 155.0; // end of green‐hill band const float rockMax = 160.0; // end of grey‐rock band const float fade = 5.0; // width of the smooth blends /*–– hash, noise & fbm ––*/ float hash(vec2 p) { p = 50.0 * fract(p * 0.3183099 + vec2(0.71, 0.113)); return fract(p.x * p.y * (p.x + p.y)); } float noise(in vec2 p) { vec2 i = floor(p), f = fract(p); vec2 u = f*f*(3.0-2.0*f); return mix( mix(hash(i), hash(i+vec2(1,0)), u.x), mix(hash(i+vec2(0,1)), hash(i+vec2(1,1)), u.x), u.y ); } float fbm(in vec2 p) { float a=0.5, t=0.0; for(int i=0;i<6;i++){ t += a*noise(p); p *= 2.2; a *= 0.5; } return t; } float ridged(in vec2 p) { float sum=0., amp=1.; for(int i=0;i<5;i++){ float n = noise(p); sum += amp * (1.0 - abs(2.0*n - 1.0)); p *= 2.3; amp *= 0.5; } return sum; } /*–– terrain height ––*/ float heightField(vec2 p) { vec2 q = p*0.0025;// + vec2(iTime*0.01, 0.0); vec2 warp = vec2(fbm(q*6.0), fbm(q*6.0+7.0))*20.0; p += warp; float h = fbm(p*0.0035)*100.0; h += ridged(p*0.005)*60.0; h += fbm(p*0.02)*15.0; // ——— flattening around waterLevel ——— const float S = 50.0; // how “wide” the smoothing band is float d = h - (waterLevel-15.0); // distance above water // t goes 0→1 as you move from waterLevel to waterLevel+S float t = clamp( d/S, 0.0, 1.0 ); // mix between dead-flat waterLevel (t=0) and your real height (t=1) h = mix( waterLevel, h, t ); return h; } float waterPlaneSDF(vec3 pos) { return pos.z - waterLevel; } /*–– SDF, normal & AO ––*/ float terrainSDF(vec3 pos) { return pos.z - heightField(pos.xy); } vec3 terrainNormal(vec3 p) { float e=0.5; vec2 o=vec2(e,0.); return normalize(vec3( heightField(p.xy+o.xy) - heightField(p.xy-o.xy), heightField(p.xy+o.yx) - heightField(p.xy-o.yx), 2.0*e )); } float calcAO(vec3 p, vec3 n) { float occ=0., sc=1.; for(int i=1;i<=5;i++){ float hr = float(i)*0.2525; float d = terrainSDF(p + n*hr); occ += (hr - d)*sc; sc *= 0.7; } return clamp(1.0 - occ*0.2, 0.0, 1.0); } /*–– camera ––*/ void getCamera(out vec3 camPos, out vec3 camDir, out vec3 camRight, out vec3 camUp, in vec2 uv) { float t = iTime*0.096; vec2 path = vec2(sin(t), 0.7*cos(t*0.8))*90.0 + vec2(t*50.0,0.); float g = heightField(path); camPos = vec3(path, g+30.0); vec3 tgt = vec3(path+vec2(45.0,0.), heightField(path+vec2(45.0,0.))+10.0); camDir = normalize(tgt - camPos); camRight = normalize(cross(vec3(0,0,1), camDir)); camUp = cross(camDir, camRight); camDir = normalize(camDir + uv.x*camRight*0.8 + uv.y*camUp*0.6); } /*–– sky, sun & clouds ––*/ vec3 sky(vec3 rd) { vec3 sunDir = normalize(vec3(0.2,0.4,0.9)); float sd = clamp(dot(rd,sunDir),0.,1.); float sun = smoothstep(0.996,1.,sd); float t = clamp(rd.z*0.5+0.5,0.,1.); vec3 col = mix(vec3(0.8,0.85,0.98), vec3(0.15,0.35,0.75), t); vec2 cuv = rd.xy/rd.z*120.0 + vec2(iTime*15.0,0.); float c = fbm(cuv*0.0007); float cl = smoothstep(0.5,0.7,c)*smoothstep(-0.2,0.5,rd.z); col = mix(col, vec3(1.0), cl*0.6); col += vec3(1.3,1.1,0.9)*pow(sun,16.0); return col; } float softShadow(vec3 ro, vec3 rd) { float res=1., t=1.; for(int i=0;i<12;i++){ float h = terrainSDF(ro + rd*t); res = min(res, 12.*h/t); t += clamp(h,0.3,5.); if(res<0.001||t>200.) break; } return clamp(res,0.,1.); } bool intersectHeightfield(in vec3 camP, in vec3 ray, out float tHit) { // initial guess: where ray would hit water plane float t = (waterLevel - camP.z) / ray.z; t = max(t, 0.0); // Newton iterations for (int i = 0; i < 5; i++) { vec2 posXY = camP.xy + ray.xy * t; float h = heightField(posXY); float f = (camP.z + ray.z * t) - h; // estimate dh/dt = dot(∇H, ray.xy) float e = 0.01; float hX = heightField(posXY + vec2(e,0.0)); float hY = heightField(posXY + vec2(0.0,e)); vec2 gradH = vec2((hX - h)/e, (hY - h)/e); float df = ray.z - dot(gradH, ray.xy); // avoid division by zero t -= f / max(df, 0.0001); if (abs(f) < 0.01) break; } if (t < 0.0 || t > 500.0) return false; tHit = t; return true; } void main() { // === pixelation: quantize to 2×2 blocks === float pixelSize = 2.0; // size of block vec2 coord = floor(gl_FragCoord.xy / pixelSize) * pixelSize; // now compute uv from the *quantized* coordinate vec2 uv = (coord * 2.0 - iResolution.xy) / iResolution.y; // === camera setup (unchanged) === vec3 camP, camD, camR, camU; getCamera(camP, camD, camR, camU, uv); vec3 ray = camD; // === rest of your ray-marching & shading === float t = 0.0; bool hit = false; bool hitWater = false; vec3 pos; for (int i = 0; i < 256*2; i++) { pos = camP + ray * t; float dTerrain = terrainSDF(pos); float dPlane = waterPlaneSDF(pos); float d = min(dTerrain, dPlane); if (d < 0.01) { hit = true; hitWater = (dPlane < dTerrain); break; } t += clamp(d * 0.5, 0.0512, 6.0); if (t > 512.0) break; } vec3 skyCol = sky(ray); vec3 col = skyCol; if (hit) { if (hitWater) { // water shading (unchanged) … vec3 wpos = pos; float w = sin((wpos.x + wpos.y) * 0.01 + iTime * 1.5) * 1.5; vec3 waveNormal = normalize(vec3(-dFdx(w), -dFdy(w), 1.0)); float fres = pow(1.0 - dot(ray, waveNormal), 5.0); vec3 waterCol = vec3(0.0, 0.0, 0.8); col = mix(waterCol, skyCol, fres * 0.7 + 0.1); } else { // terrain shading (unchanged) … vec3 n = terrainNormal(pos); vec3 sunDir = normalize(vec3(0.2,0.4,0.9)); float diff = clamp(dot(n,sunDir),0.,1.) * softShadow(pos + n*0.3, sunDir); float ao = calcAO(pos,n); float h = pos.z; float hillAmt = smoothstep(0.0, hillMax, h) * (1.0 - smoothstep(hillMax, hillMax+fade, h)); vec3 hillCol = mix( vec3(0.15,0.55,0.15), vec3(0.05,0.45,0.05), fbm(pos.xy * 0.01) ); float rockAmt = smoothstep(hillMax, rockMax, h) * (1.0 - smoothstep(rockMax, rockMax+fade, h)); vec3 rockCol = vec3(0.45) + ridged(pos.xy * 0.02) * 0.2; float peakAmt = smoothstep(rockMax, rockMax+fade, h); vec3 peakCol = vec3(1.0); float wsum = hillAmt + rockAmt + peakAmt + 1e-3; hillAmt /= wsum; rockAmt /= wsum; peakAmt /= wsum; vec3 baseCol = hillAmt*hillCol + rockAmt*rockCol + peakAmt*peakCol; col = baseCol * (0.3 + diff*1.2) * ao + pow(max(dot(reflect(-sunDir,n), ray),0.0), 64.0) * 0.3; float fog = smoothstep(0.0,1.0,t/700.0); col = mix(col, skyCol, fog); } } col = pow(col, vec3(1.0/2.2)); fragColor = vec4(col,1.0); }