#version 450 // River Flight - dr2 - 2014-11-06 // https://www.shadertoy.com/view/4sSXDG // Fasten your seatbelts for a wild ride. // "River Flight" by dr2 - 2014 // License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; vec4 OutputSize; vec4 OriginalSize; vec4 SourceSize; uint FrameCount; } global; #pragma stage vertex layout(location = 0) in vec4 Position; layout(location = 1) in vec2 TexCoord; layout(location = 0) out vec2 vTexCoord; const vec2 madd = vec2(0.5, 0.5); void main() { gl_Position = global.MVP * Position; vTexCoord = gl_Position.xy; } #pragma stage fragment layout(location = 0) in vec2 vTexCoord; layout(location = 0) out vec4 FragColor; float iGlobalTime = float(global.FrameCount)*0.025; vec2 iResolution = global.OutputSize.xy; const vec4 cHashA4 = vec4 (0., 1., 57., 58.); const vec3 cHashA3 = vec3 (1., 57., 113.); const float cHashM = 43758.54; vec4 Hashv4f (float p) { return fract (sin (p + cHashA4) * cHashM); } float Noisefv2 (vec2 p) { vec2 i = floor (p); vec2 f = fract (p); f = f * f * (3. - 2. * f); vec4 t = Hashv4f (dot (i, cHashA3.xy)); return mix (mix (t.x, t.y, f.x), mix (t.z, t.w, f.x), f.y); } float Noisefv3 (vec3 p) { vec3 i = floor (p); vec3 f = fract (p); f = f * f * (3. - 2. * f); float q = dot (i, cHashA3); vec4 t1 = Hashv4f (q); vec4 t2 = Hashv4f (q + cHashA3.z); return mix (mix (mix (t1.x, t1.y, f.x), mix (t1.z, t1.w, f.x), f.y), mix (mix (t2.x, t2.y, f.x), mix (t2.z, t2.w, f.x), f.y), f.z); } vec3 Noisev3v2 (vec2 p) { vec2 i = floor (p); vec2 f = fract (p); vec2 ff = f * f; vec2 u = ff * (3. - 2. * f); vec2 uu = 30. * ff * (ff - 2. * f + 1.); vec4 h = Hashv4f (dot (i, cHashA3.xy)); return vec3 (h.x + (h.y - h.x) * u.x + (h.z - h.x) * u.y + (h.x - h.y - h.z + h.w) * u.x * u.y, uu * (vec2 (h.y - h.x, h.z - h.x) + (h.x - h.y - h.z + h.w) * u.yx)); } float SmoothMin (float a, float b, float r) { float h = clamp (0.5 + 0.5 * (b - a) / r, 0., 1.); return mix (b, a, h) - r * h * (1. - h); } float SmoothBump (float lo, float hi, float w, float x) { return (1. - smoothstep (hi - w, hi + w, x)) * smoothstep (lo - w, lo + w, x); } float PrCapsDf (vec3 p, vec2 b) { return length (p - vec3 (0., 0., b.x * clamp (p.z / b.x, -1., 1.))) - b.y; } float PrCylDf (vec3 p, vec2 b) { return max (length (p.xy) - b.x, abs (p.z) - b.y); } float PrConeDf (vec3 p, vec3 b) { return max (dot (vec2 (length (p.xy), p.z), b.xy), abs (p.z) - b.z); } int idObj; mat3 flyerMat; vec3 flyerPos, engPos, qHit, qHitTransObj, sunDir, sunCol; vec2 trkOffset; float szFac, wSpan, tCur; const float dstFar = 400.; const float pi = 3.14159; vec3 TrackPath (float t) { return vec3 (24. * sin (0.035 * t) * sin (0.012 * t) * cos (0.01 * t) + 19. * sin (0.0032 * t) + 100. * trkOffset.x, 0., t); } float GrndHt (vec2 p, int hiRes) { const vec2 vRot = vec2 (1.4624, 1.6721); vec2 q = p * 0.06; float w = 0.75 * Noisefv2 (0.25 * q) + 0.15; w *= 36. * w; vec2 vyz = vec2 (0.); float ht = 0.; for (int j = 0; j < 10; j ++) { vec3 v = Noisev3v2 (q); vyz += v.yz; ht += w * v.x / (1. + dot (vyz, vyz)); if (j == 4) { if (hiRes == 0) break; } w *= -0.37; q *= mat2 (vRot.x, vRot.y, - vRot.y, vRot.x); } vec3 pt = TrackPath (p.y); pt.y -= 2.; float g = smoothstep (1.5, 4.5, sqrt (abs (p.x - pt.x))); return min (ht, pt.y * (1. - g) + ht * g); } vec3 GrndNf (vec3 p, float d) { float ht = GrndHt (p.xz, 1); vec2 e = vec2 (max (0.01, 0.00001 * d * d), 0.); return normalize (vec3 (ht - GrndHt (p.xz + e.xy, 1), e.x, ht - GrndHt (p.xz + e.yx, 1))); } vec4 GrndCol (vec3 p, vec3 n) { const vec3 gCol1 = vec3 (0.6, 0.7, 0.7), gCol2 = vec3 (0.2, 0.1, 0.1), gCol3 = vec3 (0.4, 0.3, 0.3), gCol4 = vec3 (0.1, 0.2, 0.1), gCol5 = vec3 (0.7, 0.7, 0.8), gCol6 = vec3 (0.05, 0.3, 0.03), gCol7 = vec3 (0.1, 0.08, 0.); vec2 q = p.xz; float f, d; float cSpec = 0.; f = 0.5 * (clamp (Noisefv2 (0.1 * q), 0., 1.) + 0.8 * Noisefv2 (0.2 * q + 2.1 * n.xy + 2.2 * n.yz)); vec3 col = f * mix (f * gCol1 + gCol2, f * gCol3 + gCol4, 0.65 * f); if (n.y < 0.5) { f = 0.4 * (Noisefv2 (0.4 * q + vec2 (0., 0.57 * p.y)) + 0.5 * Noisefv2 (6. * q)); d = 4. * (0.5 - n.y); col = mix (col, vec3 (f), clamp (d * d, 0.1, 1.)); cSpec += 0.1; } if (p.y > 22.) { if (n.y > 0.25) { f = clamp (0.07 * (p.y - 22. - Noisefv2 (0.2 * q) * 15.), 0., 1.); col = mix (col, gCol5, f); cSpec += f; } } else { if (n.y > 0.45) { vec3 c = (n.y - 0.3) * (gCol6 * vec3 (Noisefv2 (0.4 * q), Noisefv2 (0.34 * q), Noisefv2 (0.38 * q)) + vec3 (0.02, 0.1, 0.02)); col = mix (col, c, smoothstep (0.45, 0.65, n.y) * (1. - smoothstep (15., 22., p.y - 1.5 + 1.5 * Noisefv2 (0.2 * q)))); } if (p.y < 0.65 && n.y > 0.4) { d = n.y - 0.4; col = mix (col, d * d + gCol7, 2. * clamp ((0.65 - p.y - 0.35 * (Noisefv2 (0.4 * q) + 0.5 * Noisefv2 (0.8 * q) + 0.25 * Noisefv2 (1.6 * q))), 0., 0.3)); cSpec += 0.1; } } return vec4 (col, cSpec); } float GrndRay (vec3 ro, vec3 rd) { vec3 p; float h, s, sLo, sHi; s = 0.; sLo = 0.; float dHit = dstFar; for (int j = 0; j < 150; j ++) { p = ro + s * rd; h = p.y - GrndHt (p.xz, 0); if (h < 0.) break; sLo = s; s += max (0.15, 0.4 * h) + 0.008 * s; if (s > dstFar) break; } if (h < 0.) { sHi = s; for (int j = 0; j < 10; j ++) { s = 0.5 * (sLo + sHi); p = ro + s * rd; h = step (0., p.y - GrndHt (p.xz, 0)); sLo += h * (s - sLo); sHi += (1. - h) * (s - sHi); } dHit = sHi; } return dHit; } float WaterHt (vec3 p) { p *= 0.1; float ht = 0.; const float wb = 1.414; float w = 0.2 * wb; for (int j = 0; j < 7; j ++) { w *= 0.5; p = wb * vec3 (p.y + p.z, p.z - p.y, 2. * p.x); ht += w * abs (Noisefv3 (p) - 0.5); } return ht; } vec3 WaterNf (vec3 p, float d) { float ht = WaterHt (p); vec2 e = vec2 (max (0.01, 0.001 * d * d), 0.); return normalize (vec3 (ht - WaterHt (p + e.xyy), e.x, ht - WaterHt (p + e.yyx))); } vec3 SkyBg (vec3 rd) { const vec3 sbCol = vec3 (0.15, 0.2, 0.65); vec3 col; col = sbCol + 0.2 * sunCol * pow (1. - max (rd.y, 0.), 5.); return col; } vec3 SkyCol (vec3 ro, vec3 rd) { const float skyHt = 200.; vec3 col; float cloudFac; if (rd.y > 0.) { ro.x += 0.5 * tCur; vec2 p = 0.01 * (rd.xz * (skyHt - ro.y) / rd.y + ro.xz); float w = 0.65; float f = 0.; for (int j = 0; j < 4; j ++) { f += w * Noisefv2 (p); w *= 0.5; p *= 2.3; } cloudFac = clamp (5. * (f - 0.5) * rd.y - 0.1, 0., 1.); } else cloudFac = 0.; float s = max (dot (rd, sunDir), 0.); col = SkyBg (rd) + sunCol * (0.35 * pow (s, 6.) + 0.65 * min (pow (s, 256.), 0.3)); col = mix (col, vec3 (0.85), cloudFac); return col; } float GrndSShadow (vec3 ro, vec3 rd) { float sh = 1.; float d = 0.01; for (int i = 0; i < 80; i++) { vec3 p = ro + rd * d; float h = p.y - GrndHt (p.xz, 0); sh = min (sh, 20. * h / d); d += 0.5; if (h < 0.001) break; } return clamp (sh, 0., 1.); } struct WingParm { float span, sRad, trans, thck, leCut, leRad; }; float WingDf (vec3 p, WingParm wg) { vec2 q = p.yz; float w = max (length (q - vec2 (wg.sRad, 0.)), length (q + vec2 (wg.sRad, 0.))); w = max (max (w - wg.thck, abs (p.x - wg.trans) - wg.span), p.z - wg.leCut); return min (w, max (length (q - vec2 (0., wg.leCut)) - wg.leRad, abs (p.x - wg.trans) - wg.span)); } float PropelDf (vec3 p, float dHit) { vec3 q; float d; dHit /= szFac; p /= szFac; q = p; q.x = abs (q.x); q -= engPos; d = PrCylDf (q - vec3 (0., 0., 3.65), vec2 (1.9, 0.05)); if (d < dHit) { dHit = d; qHitTransObj = q; } return dHit * szFac; } float TransObjDf (vec3 p) { float dHit = dstFar; dHit = PropelDf (flyerMat * (p - flyerPos), dHit); return dHit; } float TransObjRay (vec3 ro, vec3 rd) { const float dTol = 0.001; float d; float dHit = 0.; for (int j = 0; j < 150; j ++) { d = TransObjDf (ro + dHit * rd); dHit += d; if (d < dTol || dHit > dstFar) break; } return dHit; } float FlyerDf (vec3 p, float dHit) { vec3 q; WingParm wg; float d, wr, ws, cLen; const float wSweep = 0.2; const float fusLen = 11.; const float taPos = 12.5; dHit /= szFac; p /= szFac; q = p; wr = q.z / fusLen; d = PrCapsDf (q - fusLen * vec3 (0., 0.045 + 0.08 * wr, 0.), fusLen * vec2 (0.46, 0.11)); if (d < dHit) { dHit = d; idObj = 1; qHit = q; } d = PrCapsDf (q - fusLen * vec3 (0., 0., -0.32), fusLen * vec2 (1., 0.15 - 0.051 * wr * wr)); if (d < dHit + 0.1) { dHit = SmoothMin (dHit, d, 0.1); idObj = 2; qHit = q; } ws = wSweep * abs (p.x) / wSpan; q = p + vec3 (0., 0.054 * fusLen - 6. * ws, 12. * ws); wg = WingParm (wSpan, 13.7, 0., 14., 1.72, 0.195); d = WingDf (q, wg); if (d < dHit + 0.2) { dHit = SmoothMin (dHit, d, 0.2); idObj = 3; qHit = q; } q = p + vec3 (0., -0.1 - 6. * ws, taPos + 12. * ws); wg = WingParm (0.4 * wSpan, 6.8, 0., 7., 1.2, 0.095); d = WingDf (q, wg); if (d < dHit + 0.1) { dHit = SmoothMin (dHit, d, 0.1); idObj = 4; qHit = q; } ws = wSweep * abs (p.y) / wSpan; q = p.yxz + vec3 (-0.2, 0., taPos + 12. * ws); wg = WingParm (0.15 * wSpan, 6.8, 2.2, 7., 1.2, 0.095); d = WingDf (q, wg); if (d < dHit + 0.1) { dHit = SmoothMin (dHit, d, 0.1); idObj = 5; qHit = q; } q = p; q.x = abs (q.x); cLen = 3.5; wr = q.z / cLen; d = PrCylDf (q - engPos, cLen * vec2 (0.2 - 0.07 * wr * wr, 1.)); float d2 = PrCylDf (q - engPos, cLen * vec2 (0.04, 1.02)); d = max (d, - d2); if (d < dHit) { dHit = d; idObj = 6; qHit = q; } q = p; q.x = abs (q.x); d = PrConeDf (q - engPos - vec3 (0., 0., 4.2), vec3 (0.8, 0.6, 0.7)); if (d < dHit) { dHit = d; idObj = 7; qHit = q; } q = p; cLen = 2.8; q.z += wSweep * wSpan - 0.025 * cLen; q.x = abs (q.x); wr = q.z / cLen; d = PrCapsDf (q - vec3 (wSpan + 0.1, 0.5 * wSweep * wSpan - 0.6, -0.5), cLen * vec2 (1., 0.15 - 0.055 * wr * wr)); if (d < dHit) { dHit = d; idObj = 8; qHit = q; } return 0.8 * dHit * szFac; } float ObjDf (vec3 p) { float dHit = dstFar; dHit = FlyerDf (flyerMat * (p - flyerPos), dHit); return dHit; } float ObjRay (vec3 ro, vec3 rd) { const float dTol = 0.001; float d; float dHit = 0.; for (int j = 0; j < 150; j ++) { d = ObjDf (ro + dHit * rd); dHit += d; if (d < dTol || dHit > dstFar) break; } return dHit; } vec3 ObjNf (vec3 p) { const vec3 e = vec3 (0.001, -0.001, 0.); float v0 = ObjDf (p + e.xxx); float v1 = ObjDf (p + e.xyy); float v2 = ObjDf (p + e.yxy); float v3 = ObjDf (p + e.yyx); return normalize (vec3 (v0 - v1 - v2 - v3) + 2. * vec3 (v1, v2, v3)); } float ObjSShadow (vec3 ro, vec3 rd) { float sh = 1.; float d = 0.07 * szFac; for (int i = 0; i < 50; i++) { float h = ObjDf (ro + rd * d); sh = min (sh, 20. * h / d); d += 0.07 * szFac; if (h < 0.001) break; } return clamp (sh, 0., 1.); } vec3 ObjCol (vec3 p, vec3 n) { vec3 bCol = vec3 (0.8, 0.8, 0.85), wCol = vec3 (0.3, 0.3, 0.7), tCol = vec3 (0.9, 0.7, 0.), uCol = vec3 (0.9, 0.1, 0.); float cFac = 1.; if (idObj >= 3 && idObj <= 5) { float s1, s2; if (idObj == 3) { s1 = 2.2; s2 = 6.; } else if (idObj == 4) { s1 = 1.2; s2 = 1.7; } else if (idObj == 5) { s1 = 1.; s2 = 1.; } if (abs (qHit.x) > s2 - 0.03) cFac = 1. - 0.9 * SmoothBump (- 0.08, 0.08, 0.02, qHit.z + s1); if (qHit.z < - s1) cFac = 1. - 0.9 * SmoothBump (- 0.05, 0.05, 0.02, abs (qHit.x) - s2); } vec3 col; vec3 nn; if (idObj >= 1 && idObj <= 5) nn = flyerMat * n; if (idObj == 1 || idObj == 2) { col = mix (uCol, bCol, 1. - smoothstep (-0.6, 0., nn.y)); if (idObj == 2 && nn.y < 0.) col = mix (bCol, wCol, SmoothBump (-0.8, 0.8, 0.3, qHit.z + 0.28)); } else if (idObj == 3 || idObj == 4) { col = mix (bCol, wCol, SmoothBump (-0.8, 0.8, 0.3, qHit.z)); } else if (idObj == 5) { col = mix (bCol, tCol, SmoothBump (-0.6, 0.8, 0.3, qHit.z)); } else if (idObj == 6) { col = bCol; } else if (idObj == 7 || idObj == 8) { col = tCol; } if (idObj == 1) { if (qHit.z > 4.5 && abs (qHit.x) > 0.07) idObj = 10; } else if (idObj == 2) { float s = - qHit.z; if (s > 0. && s < 9.) { vec2 ws = vec2 (qHit.y - 0.5, mod (s + 1.5, 1.5) - 0.75); ws *= ws; if (dot (ws, ws) < 0.02) idObj = 10; } } return col * cFac; } vec3 ShowScene (vec3 ro, vec3 rd) { const float eps = 0.01; vec4 col4; vec3 objCol, col, vn; float dstHit, dstGrnd, dstObj, dstPropel, f; int idObjT; vec3 roo = ro; dstHit = dstFar; dstGrnd = GrndRay (ro, rd); wSpan = 12.; engPos = vec3 (0.35 * wSpan, -0.2, -1.5); idObj = 0; dstObj = ObjRay (ro, rd); idObjT = idObj; dstPropel = TransObjRay (ro, rd); if (dstObj < dstPropel) dstPropel = dstFar; float refFac = 1.; if (dstGrnd < dstObj && ro.y + dstGrnd * rd.y < 0.) { float dw = - ro.y / rd.y; ro += dw * rd; rd = reflect (rd, WaterNf (ro, dw)); ro += eps * rd; dstGrnd = GrndRay (ro, rd); idObj = 0; dstObj = ObjRay (ro, rd); idObjT = idObj; refFac *= 0.6; } bool isGrnd = false; if (dstObj < dstGrnd) { ro += dstObj * rd; vn = ObjNf (ro); idObj = idObjT; objCol = ObjCol (ro, vn); if (idObj == 10) objCol = vec3 (0.2) + 0.5 * SkyCol (ro, reflect (rd, vn)); float dif = max (dot (vn, sunDir), 0.); col = sunCol * objCol * (0.2 * (1. + max (dot (vn, - normalize (vec3 (sunDir.x, 0., sunDir.z))), 0.)) + max (0., dif) * ObjSShadow (ro, sunDir) * (dif + 0.5 * pow (max (0., dot (sunDir, reflect (rd, vn))), 100.))); dstHit = dstObj; } else { vec3 rp = ro + dstGrnd * rd; if (refFac < 1.) dstHit = length (rp - roo); else dstHit = dstGrnd; if (dstHit < dstFar) { ro = rp; isGrnd = true; } else { col = refFac * SkyCol (ro, rd); } } if (isGrnd) { vn = GrndNf (ro, dstHit); col4 = GrndCol (ro, vn); col = col4.xyz * refFac; float dif = max (dot (vn, sunDir), 0.); col *= sunCol * (0.2 * (1. + max (dot (vn, - normalize (vec3 (sunDir.x, 0., sunDir.z))), 0.)) + max (0., dif) * GrndSShadow (ro, sunDir) * (dif + col4.w * pow (max (0., dot (sunDir, reflect (rd, vn))), 100.))); } if (dstPropel < dstFar) col = 0.7 * col + 0.1 - 0.04 * SmoothBump (1.5, 1.7, 0.02, length (qHitTransObj.xy)); if (dstHit < dstFar) { f = dstHit / dstFar; col = mix (col, refFac * SkyBg (rd), clamp (1.03 * f * f, 0., 1.)); } col = sqrt (clamp (col, 0., 1.)); return clamp (col, 0., 1.); } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = 2. * fragCoord.xy / iResolution.xy - 1.; vec2 uvs = uv; uv.x *= iResolution.x / iResolution.y; trkOffset = vec2 (0.); float zmFac = 2.7; tCur = 15. * iGlobalTime + 100. * trkOffset.y; sunDir = normalize (vec3 (0.9, 1., 0.4)); sunCol = vec3 (1., 0.9, 0.8); vec3 ro, rd, vd, fpF, fpB, vDir; szFac = 0.25; float dt = 1.; fpF = TrackPath (tCur + dt); flyerPos = TrackPath (tCur); fpB = TrackPath (tCur - dt); vec3 vel = (fpF - fpB) / (2. * dt); vel.y = 0.; vec3 acc = (fpF - 2. * flyerPos + fpB) / (dt * dt); acc.y = 0.; vec3 va = cross (acc, vel) / length (vel); float roll = 12. * length (va); if (va.y < 0.) roll *= -1.; vDir = normalize (vel); float cRl = cos (roll); float sRl = sin (roll); flyerMat = mat3 (cRl, - sRl, 0., sRl, cRl, 0., 0., 0., 1.) * mat3 (vDir.z, 0., vDir.x, 0., 1., 0., - vDir.x, 0., vDir.z); float vuPeriod = 500.; flyerPos.y = 3. + 1.5 * sin (2.5 * tCur / vuPeriod); float lookDir = 2. * mod (floor (tCur / vuPeriod), 2.) - 1.; ro = TrackPath (tCur - 40. * lookDir * (1. - 0.8 * abs (sin (pi * mod (tCur, vuPeriod) / vuPeriod)))); ro.y = 3. + 0.6 * sin (0.16 * tCur / vuPeriod); vd = flyerPos - ro; vd.y = 0.; vd = normalize (lookDir * vDir + 0.3 * normalize (vd)); mat3 scMat = mat3 (vd.z, 0., - vd.x, 0., 1., 0., vd); rd = scMat * normalize (vec3 (uv, zmFac)); vec3 col = ShowScene (ro, rd); uvs *= uvs * uvs; col = mix (vec3 (0.7), col, pow (max (0., 0.95 - length (uvs * uvs * uvs)), 0.3)); fragColor = vec4 (col, 1.); } void main(void) { //just some shit to wrap shadertoy's stuff vec2 FragmentCoord = vTexCoord.xy*global.OutputSize.xy; FragmentCoord.y = -FragmentCoord.y; mainImage(FragColor,FragmentCoord); }