#extension GL_OES_standard_derivatives : enable /* _ _ _ ____ _ _ / \ | (_) ___ _ __ / ___| _ __ __ _ ___ ___ ___| |__ (_)_ __ / _ \ | | |/ _ \ '_ \ \___ \| '_ \ / _` |/ __/ _ \/ __| '_ \| | '_ \ / ___ \| | | __/ | | | ___) | |_) | (_| | (_| __/\__ \ | | | | |_) | /_/ \_\_|_|\___|_| |_| |____/| .__/ \__,_|\___\___||___/_| |_|_| .__/ |_| |_| Alien Spaceship by @gam0022 Released at GLSL Graphics Compo, Tokyo Demo Fest 2021 */ // BEGIN: shadertoy porting template // https://gam0022.net/blog/2019/03/04/porting-from-shadertoy-to-glslsandbox/ precision highp float; uniform vec2 resolution; uniform float time; uniform vec2 mouse; uniform sampler2D backbuffer; #define iResolution resolution #define iTime time #define iMouse (vec4(mouse, 0.5, 0.5) * resolution.xyxy) #define iChannel0 backbuffer #define texture texture2D void mainImage(out vec4 fragColor, in vec2 fragCoord); void main(void) { vec4 col; mainImage(col, gl_FragCoord.xy); gl_FragColor = col; } // END: shadertoy porting template #define BPM 114.0 #define TAU 6.28318530718 #define saturate(x) clamp(x, 0., 1.) #define opRep(p, a) p = mod(p, a) - a * 0.5 #define opRepLim(p, c, l) p = p - c * clamp(floor(p / c + 0.5), -l, l); vec3 ro, target; float fov; vec3 scol; float beat; float beatTau; // For Debugging vec4 PU; // [ 0 1] vec4 PN; // [-1 1] // Timeline float prevEndTime = 0., t = 0.; #define TL(beat, end) if (t = beat - prevEndTime, beat < (prevEndTime = end)) // Material Types #define VOL 0.0 #define SOL 1.0 // https://www.shadertoy.com/view/3tX3R4 float remap(float val, float im, float ix, float om, float ox) { return clamp(om + (val - im) * (ox - om) / (ix - im), om, ox); } float remap01(float val, float im, float ix) { return saturate((val - im) / (ix - im)); } void opUnion(inout vec4 m, float d, float type, float roughness_or_emissive, float hue) { if (d < m.x) m = vec4(d, type, roughness_or_emissive, hue); } vec3 pal(vec4 m) { // Integer part: Blend ratio with white (0-10) // Decimal part: Hue (0-1) vec3 col = vec3(0.5) + 0.5 * cos(TAU * (vec3(0.0, 0.33, 0.67) + m.w)); return mix(col, vec3(1), 0.1 * floor(m.w)); } // Ref. Energy Lab by kaneta // https://www.shadertoy.com/view/3dd3WB float smoothPulse(float start, float end, float period, float smoothness, float t) { float h = abs(end - start) * 0.5; t = mod(t, period); return smoothstep(start, start + h * smoothness, t) - smoothstep(end - h * smoothness, end, t); } // Hash without Sine by David Hoskins. // https://www.shadertoy.com/view/4djSRW float hash12(vec2 p) { vec3 p3 = fract(vec3(p.xyx) * .1031); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.x + p3.y) * p3.z); } vec2 hash23(vec3 p3) { p3 = fract(p3 * vec3(.1031, .1030, .0973)); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.xx + p3.yz) * p3.zy); } // hemisphere hash function based on a hash by Slerpy vec3 hashHs(vec3 n, vec3 seed) { vec2 h = hash23(seed); float a = h.x * 2. - 1.; float b = TAU * h.y * 2. - 1.; float c = sqrt(1. - a * a); vec3 r = vec3(c * cos(b), a, c * sin(b)); return r; } // https://www.shadertoy.com/view/lssGWn float sdEgg(vec3 p, float r) { p.y *= 0.8; p.y += 0.15 * pow(1.5 * dot(p.xz, p.xz), 0.6); return length(p) - r; } float sdBox(vec3 p, vec3 b) { vec3 q = abs(p) - b; return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0); } void rot(inout vec2 p, float a) { p *= mat2(cos(a), sin(a), -sin(a), cos(a)); } vec4 map(vec3 pos) { vec4 m = vec4(1, VOL, 0, 0); // x: Distance // y: MaterialType (VOL or SOL) // z: Roughness in (0-1), Emissive when z>1 // w: ColorPalette float roughness = 0.05; float a = 1.; float W = 8.; float H = 4.; float D = 8.; // Final Room if (pos.z >= D * 6.) { W *= 2.; H *= 2.; D *= 2.; roughness = 0.3; } vec3 p1 = pos, p; p1.x = abs(p1.x); opRep(p1.z, 2. * D); float roomID = max(floor(pos.z / (2. * D)), 0.0); // egg p = p1; opUnion(m, sdEgg(p - vec3(0, 1, 0), 1.), SOL, 0.01, 0.0); // floor float pz = smoothPulse(0.0, 0.6, 1.0, 0.5, 0.25 * p.z); float emi = smoothPulse(0.2, 0.25, 1.0, 0.5, pz + p.x / 2.0) * saturate(sin(beatTau / 8. + pos.z)) * step(4., beat); float h = a + 0.1 * floor(2. * sin(p.x)) + 0.2 * floor(1. * sin(2. * p.z)); opUnion(m, sdBox(p - vec3(0, -a, 0), vec3(W, h, D)), SOL, roughness + 2. * emi, 0.4); // door innner emi = 2. * step(beat, 4. * 16.); float py = smoothPulse(0.0, 0.6, 1.0, 0.5, 0.25 * p.y); emi += 1.8 * smoothPulse(0.0, 0.25, 1.0, 0.5, py + 0.5 * p.x) * saturate(sin(beatTau / 8. + pos.y / 4. - py)); opUnion(m, sdBox(p - vec3(0, H - a, D - 2. * a), vec3(W, H, 0.5 * a)), VOL, emi, 2.0 + fract(0.9 + 0.325 * roomID)); // door outer p.x = pos.x; p.x -= 0.5 * (smoothPulse(0.0, 0.6, 1.0, 0.5, 0.3 * p.y) - 0.5); /* float doorOpen = 0.05 * saturate(beat / 4.); if (roomID < 2.) doorOpen += remap(beat, 4. * 16., 4. * 18., 0.0, 0.9); else doorOpen += remap(beat, 4. * 32., 4. * 36., 0.0, 0.9); */ float openStart = 16. + step(2., roomID) * 18.; float doorOpen = 0.05 * saturate(beat / 4.) + 0.9 * (1. - exp(-3. * remap01(beat, 4. * openStart, 4. * (openStart + 2.)))); float doorPX = (0.5 + 0.5 * doorOpen) * W; opUnion(m, sdBox(p - vec3(doorPX, H - a, D - 2. * a), vec3(0.5 * W, H, a)), SOL, 0.1, -0.5); opUnion(m, sdBox(p - vec3(-doorPX, H - a, D - 2. * a), vec3(0.5 * W, H, a)), SOL, 0.1, -0.5); // wall light p = p1; opUnion(m, sdBox(p - vec3(W + a, 0.5 * H + a, 0), vec3(a, H, D)), SOL, 0.1, 0.0); opRep(p.z, 2.); p.y -= H * 0.5 + a; p.x -= W - 0.5 * abs(p.y); float freq = 0.25 * step(4. * 4., beat) + 0.75 * step(4. * 8., beat) - 0.75 * step(4. * 16., beat); float rand = TAU * step(4. * 16., beat) * hash12(floor(pos.xz / vec2(W, 2.0))); emi = 1.8 * saturate(sin(beatTau * freq + 0.5 * step(4. * 4., beat) * pos.z * TAU / D + rand)); opUnion(m, sdBox(p, vec3(a * 2., H, 0.2)), VOL, roughness + emi, 2.0 + fract(0.4 + 0.325 * roomID)); opUnion(m, sdBox(p, vec3(a * 1.7, H, 0.24)), SOL, roughness, 0.0); // wall detail p = p1; opRep(p.z, 0.5); p.y -= H * 0.5 + a; p.x -= W - 0.5 * abs(p.y) - 0.3 * floor(0.8 * abs(p.y)); opUnion(m, sdBox(p, vec3(a * 0.8, H, 0.06)), SOL, 2. * roughness, 0.0); // ceil light p = p1; p.z -= -2. * a; opRepLim(p.z, 4., 1.); p.x -= W * 0.21; opRepLim(p.x, 0.4, 1.); emi = 1.8 * step(12., beat); opUnion(m, sdBox(p - vec3(0.0, 2.0 * H - 1.1, 0), vec3(0.05, 0.1, 1.)), SOL, emi, 10.0); // ceil detail p = p1; opRep(p.x, 1.0); p.y -= 2. * H + 0.1 * smoothPulse(0.0, 0.6, 1.0, 0.5, 0.5 * p.z); p.y -= -0.4 * smoothPulse(0.0, 0.6, 1.0, 0.5, p1.x / W * 2. + 0.4); p.x -= 0.1 * smoothPulse(0.0, 0.6, 1.0, 0.5, p.z); opUnion(m, sdBox(p, vec3(0.4, 1.0, D)), SOL, roughness, 0.0); // IFS if (pos.z >= D * 3.) { vec4 ifs = vec4(875, 482, 197, 545) / vec2(1200, 675).xyxy; // ifs = PU; p = pos; p -= vec3(0, H, 16. * 3.5); for (int i = 0; i < 5; i++) { p = abs(p) - ifs.w; rot(p.xz, -4. * ifs.x); p = abs(p) - ifs.z; rot(p.xy, -4. * ifs.y); } opUnion(m, sdEgg(p, 0.1), SOL, 0.0, 0.0); opUnion(m, sdBox(p, vec2(1, 0.01).xyy), SOL, roughness, 0.0); opUnion(m, sdBox(p - vec2(0.001, 0).yxy, vec2(1, 0.01).xyy), VOL, 2.4 * saturate(cos(beatTau / 2. + 10. * p.x)), 2.4); } return m; } vec3 normal(vec3 p) { vec2 e = vec2(0, .05); return normalize(map(p).x - vec3(map(p - e.yxx).x, map(p - e.xyx).x, map(p - e.xxy).x)); } // https://www.shadertoy.com/view/tltGWj /*vec3 normal(vec3 p) { float delta = 0.1; vec4 n = vec4(0.0); for (int i = min(iFrame, 0); i < 4; i++) { vec4 s = vec4(p, 0.0); s[i] += delta; n[i] = map(s.xyz).x; } return normalize(n.xyz - n.w); }*/ // Ref. EOT - Grid scene by Virgill // https://www.shadertoy.com/view/Xt3cWS void madtracer(vec3 ro1, vec3 rd1, float seed) { scol = vec3(0); float t = 0., t2 = 0.; vec4 m1, m2; vec3 rd2, ro2, nor2; for (int i = 0; i < 160; i++) { m1 = map(ro1 + rd1 * t); // t += m1.y == VOL ? 0.25 * abs(m1.x) + 0.0008 : 0.25 * m1.x; t += 0.25 * mix(abs(m1.x) + 0.0032, m1.x, m1.y); ro2 = ro1 + rd1 * t; nor2 = normal(ro2); rd2 = mix(reflect(rd1, nor2), hashHs(nor2, vec3(seed, i, iTime)), saturate(m1.z)); m2 = map(ro2 + rd2 * t2); // t2 += m2.y == VOL ? 0.25 * abs(m2.x) : 0.25 * m2.x; t2 += 0.25 * mix(abs(m2.x), m2.x, m2.y); scol += .007 * (pal(m2) * step(1., m2.z) + pal(m1) * step(1., m1.z)); // force disable unroll for WebGL 1.0 if (t < -1.) break; } } void raymarching(vec3 ro1, vec3 rd1) { scol = vec3(0); float t = 0.; vec4 m; for (int i = 0; i < 160; i++) { vec3 p = ro1 + rd1 * t; m = map(p); t += m.x; if (m.x < 0.01) { vec3 light = normalize(vec3(1, 1, -1)); vec3 albedo = vec3(0.3); if (m.z > 1.) albedo = pal(m); scol = albedo * (0.5 + 0.5 * saturate(dot(normal(p), light))); break; } } } void setCamera(vec4 v, float roY) { vec4 u = v / vec2(1200, 675).xyxy; vec4 n = u * 2. - 1.; ro = vec3(8. * n.z, roY, 16. * u.w); target = ro + vec3(2. * n.xy, 1); } void setCameraRot(vec4 v, float roY) { vec4 u = v / vec2(1200, 675).xyxy; vec4 n = u * 2. - 1.; ro = vec3(8. * n.z, roY, 16. * u.w); vec3 fwd = vec3(0, 0, 1); rot(fwd.xz, n.x * TAU / 2.); rot(fwd.yz, n.y * TAU / 4.); target = ro + fwd; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { beat = iTime * BPM / 60.0; // beat += 4. * 36.; // beat += 32.; beat -= 4. * 4.; beatTau = beat * TAU; PU = abs(iMouse / iResolution.xyxy); // [0 1] zwはマイナスっぽいのでabsをつける PN = PU * 2. - 1.; // [-1 1] vec2 uv = fragCoord.xy / iResolution.xy; // Camera vec2 noise = hash23(vec3(iTime, fragCoord)) - 0.5; // AA vec2 uv2 = (2. * (fragCoord.xy + noise) - iResolution.xy) / iResolution.x; float FD = 675. * 3.; // Final Room Depth fov = 120.; // #define DEBUG_CAMERA #ifdef DEBUG_CAMERA setCamera(abs(iMouse) + 1. * vec4(0, 0, 0, FD), 5.0); // setCameraRot(abs(iMouse), 3.); #else // Room1 TL(beat, 4. * 8.) setCamera(vec4(600, 250. + t * 3., 600, 243. - t * 6.), 3.); else TL(beat, 4. * 10.) setCamera(vec4(600, 307, 600, 44. + t * 4.), 3.); else TL(beat, 4. * 12.) setCamera(vec4(494, 322, 695, 216), 2.4 + 0.2 * t); else TL(beat, 4. * 14.) setCamera(vec4(600, 481. + 10. * t, 600, 59), 3.); else TL(beat, 4. * 16.) setCamera(vec4(909, 158. - 10.0 * t, 470. + 10.0 * t, 158), 3.); else TL(beat, 4. * 18.) setCamera(vec4(541, 335., 609., 384. + 2.0 * t), 3.); // Room2-4 else TL(beat, 4. * 36.) setCamera(vec4(541, 335., 609., 480. + 20.0 * t), 3.); // Final else TL(beat, 4. * 40.) setCamera(vec4(572., 335. + 5. * t, 617., 106. + FD + t), 2.); // 見上げる else TL(beat, 4. * 44.) setCamera(vec4(572., 375. + 0. * t, 617., 106. + FD), mix(8., 2., exp(-0.1 * t))); // 上昇 else TL(beat, 4. * 46.) setCamera(vec4(585. + 2. * t, 268., 705., 205. + FD + 3. * t), 10.); // 高所の前進 else TL(beat, 4. * 48.) setCamera(vec4(593., 319., 622., 322. + FD - 3. * t), mix(10., 9., exp(-0.1 * t))); // 高所の後退 else TL(beat, 4. * 50.) setCamera(vec4(880., 0., 452., 166. + FD), mix(7., 14., exp(-0.5 * t))); // 落下 else TL(beat, 4. * 52.) setCamera(vec4(525. + 3. * t, 256., 704., 70. + FD + t), 5.); // 入口から俯瞰(右) else TL(beat, 4. * 54.) setCamera(vec4(733. + 3. * t, 241., 447., 133. + FD + t), 5.); // 入口から俯瞰(左) else TL(beat, 4. * 56.) setCamera(vec4(492. + 2. * t, 319., 750., 181. + FD), 4.); // 柱(右) else TL(beat, 4. * 60.) setCamera(vec4(593., 319., 622., 322. + FD + t), 3.); // 中央から前進 else TL(beat, 4. * 62.) setCamera(vec4(884., 131., 452., 216. + FD), mix(2., 4., exp(-0.1 * t))); // 落下 else TL(beat, 4. * 64.) setCamera(vec4(435., 354., 494., 216. + FD + 2. * t), 1.); // 地面を前進(左) else TL(beat, 4. * 66.) setCamera(vec4(1039., 294., 463. + 5. * t, 247. + FD), 1.); // 地面を右移動 else TL(beat, 4. * 68.) setCamera(vec4(567., 391., 664., 256. + FD + 2. * t), 1.); // 地面の中央を前進 else TL(beat, 4. * 70.) setCamera(vec4(645., 326., 705., 270. + FD), 1.9); // 卵に注目 else TL(beat, 4. * 72.) { setCamera(vec4(645, 326., 705., FD + 272.), 1.9); fov = mix(90., 120., exp(-t)); } #endif vec3 up = vec3(0, 1, 0); vec3 fwd = normalize(target - ro); vec3 right = normalize(cross(up, fwd)); up = normalize(cross(fwd, right)); vec3 rd = normalize(right * uv2.x + up * uv2.y + fwd / tan(fov * TAU / 720.)); // #define DEBUG_SCENE #ifdef DEBUG_SCENE raymarching(ro, rd); fragColor = vec4(scol, 1.); #else madtracer(ro, rd, hash12(uv2)); vec3 bufa = texture(iChannel0, uv).xyz; scol = mix(scol, vec3(0), remap01(beat, 4. * 70., 4. * 72.)); fragColor = saturate(vec4(0.7 * scol + 0.7 * bufa, 0.)); #endif }