#version 410 core uniform float fGlobalTime; // in seconds uniform vec2 v2Resolution; // viewport resolution (in pixels) uniform sampler1D texFFT; // towards 0.0 is bass / lower freq, towards 1.0 is higher / treble freq uniform sampler1D texFFTSmoothed; // this one has longer falloff and less harsh transients uniform sampler2D texBirds; uniform sampler2D texGrass; uniform sampler2D texNormal; uniform sampler2D texPerlin; uniform sampler2D texTiles; uniform sampler2D texZigZag; layout(location = 0) out vec4 out_color; // out_color must be written in order to see anything const float PI = 3.14159; float time; #define R(a,t) (vec2(sin(t) * a.x, cos(t) * a.y)) float _d; int _mID; // minimal spheretracer setup: smallest distance we have seen so far and material ID at that point // if we find a closer distance, store distance and material ID float minMat(float d, int id) { if (d < _d) { _d = d; _mID = id; } return _d; } float maxMat(float d, int id) { if (d > _d) { _d = d; _mID = id; } return _d; } // distances float the_ball(vec3 p) { return length(p) - (2 + texture(texFFT,0.1).r * 50); } float the_cube(vec3 p) { vec3 q = abs(p); //return min(q.x,q.y,q.z); return 0; } float the_trough(vec3 p) { return length(p.xy) - 3; } float the_floor(vec3 p) { return p.y + 1.0; } float the_orbiters(vec3 p) { float rho = atan(p.x,p.y) - 3; float theta = length(p.xy) - .5; return length(vec2(rho,theta) - .2); } // combined scene float scene(vec3 p) { float d = 999999; d = minMat(the_floor(p), 1); d = maxMat(-the_trough(p), 1); d = minMat(the_ball(p + vec3(sin(time),1.4*cos(2.7*time),0)), 0); // second parameter is material ID d = minMat(the_orbiters(p), 0); return d; } vec3 calcBallNormal( vec3 v ) { vec3 n; float e = 0.0001; n.x = the_ball( v + vec3(e,0,0) ) - the_ball( v - vec3(e,0,0) ); n.y = the_ball( v + vec3(0,e,0) ) - the_ball( v - vec3(0,e,0) ); n.z = the_ball( v + vec3(0,0,e) ) - the_ball( v - vec3(0,0,e) ); return normalize(n); } vec3 calcBallLighting( vec3 p, vec3 camPos ) { vec3 norm = calcBallNormal(p); vec3 lightDir = normalize(vec3(sin(5*time),1,-1)); float diff = dot(lightDir,norm); diff = clamp( diff,0.0,1.0); vec3 V = normalize( camPos - p ); vec3 L = lightDir; vec3 H = normalize( V + L ); float specular = dot(H,norm); specular = clamp( specular, 0.0, 1.0 ); return vec3(abs(sin(time)),abs(sin(3*time)),abs(cos(2*time))) * diff + pow( specular, 16 ); } void main(void) { vec2 uv = gl_FragCoord.xy / v2Resolution; float aspect = v2Resolution.x / v2Resolution.y; time = fGlobalTime; //uv.y += .1*fGlobalTime; vec2 a = (5*uv - fract(5*uv)); time += a.x - a.y; float fCamTime = time / 3.0; vec3 camPos = vec3(sin(fCamTime)*6,2,cos(fCamTime)*6); vec3 camDir = normalize(vec3(sin(fCamTime + PI),-0.4,cos(fCamTime + PI))); vec3 camUp = vec3(0,1,0); float camFovTan = tan(60.0 * PI/360); vec2 sc = (uv*2 - vec2(1)) * vec2(aspect,1); vec3 rayDir = normalize(mat3(cross(camDir,camUp), camUp, -camDir) * normalize(vec3(sc, -1/camFovTan))); // march ray float numSteps = 100; float maxDist = 1000; float t = 0; float i = 0; for (; i < 1; i+= 1/numSteps) { _d = 100000; scene(camPos + rayDir * t); if ((abs(_d) / t < camFovTan/v2Resolution.y) || (t > maxDist)) break; t += _d; } vec3 fogcolor = mix(vec3(0,0,0),vec3(0,0.5,1),uv.y) * (.3+100*texture(texFFT,.2).r); if ((t > maxDist) || (i >= 1)) { // ray missed, paint background out_color.rgb = fogcolor; } else { // ray hit, select material vec3 p = camPos + rayDir * t; switch(_mID) { case 0: out_color.rgb = calcBallLighting( p, camPos ); break; case 1: p.z+=10.*time; out_color.rgb = vec3(1,1,1) * ((mod(p.x,2) < 1) == (mod(p.z,2) < 1) ? 1 : 0.1); out_color.rgb *= .5+2*texture(texFFT,0.1).r; break; } } out_color.rgb = mix(fogcolor,out_color.rgb,exp(-t/30)); // gamma adjust //out_color.rgb += pow(vec3(1-fract(10*time)),2); //vec2 c = vec2(1,.5)*uv; //c = R(c,fGlobalTime); vec2 c = R(uv,time); out_color.rgb *= vec3(1)-texture(texZigZag,c+vec2(0,-time)).rgb; out_color.rgb = pow(out_color.rgb, vec3(1/(2.2+100.*texture(texFFTSmoothed,.1).r))); }