#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 _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; } // distances float the_ball(vec3 p) { return length(p) - (1 + texture(texFFT,0.1).r * 50); } float the_floor(vec3 p) { return p.y + 1.0; } // combined scene float scene(vec3 p) { float d = 999999; d = minMat(the_ball(p), 0); // second parameter is material ID d = minMat(the_floor(p), 1); 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(-1,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(1,0,0) * diff + pow( specular, 16 ); } bool wheel(vec2 v, float n, float t) { return fract(atan(v.x,v.y)/6.28*n+t) > 0.5; } void main(void) { vec2 uv = gl_FragCoord.xy / v2Resolution.y; float aspect = v2Resolution.x / v2Resolution.y; uv -= vec2(0.8,0.5); float time = fGlobalTime; vec3 color = wheel(uv, 6, time) ? vec3(1.0,0.8,0) : vec3(0.8,0.5,0); vec2 s = fract(uv*4.0)-0.5; int ii = int(uv.x*4.0-s.x)+int(uv.y*4.0-s.y)+3; float r = 0.2 + max(0,cos((fract(time)*6.0) - float(ii)))*0.3; if (length(s) < r) { if (length(s) < r*0.2) { color = vec3(sin(time*40.0)); } else { color = wheel(s, 6, -time) ? vec3(0.0,0.8,1) : vec3(0,0.5,1); } } vec2 ss = fract(uv*8.0-vec2(time*3.0,time*0.67))-0.5; int ii2 = int(uv.x*4.0-s.x)-int(uv.y*4.0-s.y)+3; float r2 = 0.2 + cos((fract(time)*6.0) - float(ii2))*0.2; float ff = max(abs(ss.x),abs(ss.y)); if (ff < r2 && ff > r2*0.5) { float ll = r2*r2*r2*9.0+0.4; color = vec3(ll,1,ll); } out_color = vec4(color,1); return; float fCamTime = fGlobalTime / 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; } if ((t > maxDist) || (i >= 1)) { // ray missed, paint background out_color.rgb = mix(vec3(0,0,0),vec3(0,0.5,1),uv.y); } else { // ray hit, select material vec3 p = camPos + rayDir * t; switch(_mID) { case 0: out_color.rgb = calcBallLighting( p, camPos ); break; case 1: out_color.rgb = vec3(1,1,1) * ((mod(p.x,2) < 1) == (mod(p.z,2) < 1) ? 1 : 0.1); break; } } // gamma adjust out_color.rgb = pow(out_color.rgb, vec3(1/2.2)); }